1/* 2 * tkCanvWind.c -- 3 * 4 * This file implements window items for canvas widgets. 5 * 6 * Copyright (c) 1992-1994 The Regents of the University of California. 7 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 8 * 9 * See the file "license.terms" for information on usage and redistribution 10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id: tkCanvWind.c,v 1.9.2.2 2006/05/12 18:17:55 das Exp $ 13 */ 14 15#include <stdio.h> 16#include "tkInt.h" 17#include "tkPort.h" 18#include "tkCanvas.h" 19 20/* 21 * The structure below defines the record for each window item. 22 */ 23 24typedef struct WindowItem { 25 Tk_Item header; /* Generic stuff that's the same for all 26 * types. MUST BE FIRST IN STRUCTURE. */ 27 double x, y; /* Coordinates of positioning point for 28 * window. */ 29 Tk_Window tkwin; /* Window associated with item. NULL means 30 * window has been destroyed. */ 31 int width; /* Width to use for window (<= 0 means use 32 * window's requested width). */ 33 int height; /* Width to use for window (<= 0 means use 34 * window's requested width). */ 35 Tk_Anchor anchor; /* Where to anchor window relative to 36 * (x,y). */ 37 Tk_Canvas canvas; /* Canvas containing this item. */ 38} WindowItem; 39 40/* 41 * Information used for parsing configuration specs: 42 */ 43 44static Tk_CustomOption stateOption = { 45 (Tk_OptionParseProc *) TkStateParseProc, 46 TkStatePrintProc, (ClientData) 2 47}; 48static Tk_CustomOption tagsOption = { 49 (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, 50 Tk_CanvasTagsPrintProc, (ClientData) NULL 51}; 52 53static Tk_ConfigSpec configSpecs[] = { 54 {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, 55 "center", Tk_Offset(WindowItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, 56 {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, 57 "0", Tk_Offset(WindowItem, height), TK_CONFIG_DONT_SET_DEFAULT}, 58 {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, 59 (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, 60 &stateOption}, 61 {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, 62 (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, 63 {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, 64 "0", Tk_Offset(WindowItem, width), TK_CONFIG_DONT_SET_DEFAULT}, 65 {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL, 66 (char *) NULL, Tk_Offset(WindowItem, tkwin), TK_CONFIG_NULL_OK}, 67 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, 68 (char *) NULL, 0, 0} 69}; 70 71/* 72 * Prototypes for procedures defined in this file: 73 */ 74 75static void ComputeWindowBbox _ANSI_ARGS_((Tk_Canvas canvas, 76 WindowItem *winItemPtr)); 77static int ConfigureWinItem _ANSI_ARGS_((Tcl_Interp *interp, 78 Tk_Canvas canvas, Tk_Item *itemPtr, int objc, 79 Tcl_Obj *CONST objv[], int flags)); 80static int CreateWinItem _ANSI_ARGS_((Tcl_Interp *interp, 81 Tk_Canvas canvas, struct Tk_Item *itemPtr, 82 int objc, Tcl_Obj *CONST objv[])); 83static void DeleteWinItem _ANSI_ARGS_((Tk_Canvas canvas, 84 Tk_Item *itemPtr, Display *display)); 85static void DisplayWinItem _ANSI_ARGS_((Tk_Canvas canvas, 86 Tk_Item *itemPtr, Display *display, Drawable dst, 87 int x, int y, int width, int height)); 88static void ScaleWinItem _ANSI_ARGS_((Tk_Canvas canvas, 89 Tk_Item *itemPtr, double originX, double originY, 90 double scaleX, double scaleY)); 91static void TranslateWinItem _ANSI_ARGS_((Tk_Canvas canvas, 92 Tk_Item *itemPtr, double deltaX, double deltaY)); 93static int WinItemCoords _ANSI_ARGS_((Tcl_Interp *interp, 94 Tk_Canvas canvas, Tk_Item *itemPtr, int objc, 95 Tcl_Obj *CONST objv[])); 96static void WinItemLostSlaveProc _ANSI_ARGS_(( 97 ClientData clientData, Tk_Window tkwin)); 98static void WinItemRequestProc _ANSI_ARGS_((ClientData clientData, 99 Tk_Window tkwin)); 100static void WinItemStructureProc _ANSI_ARGS_(( 101 ClientData clientData, XEvent *eventPtr)); 102static int WinItemToArea _ANSI_ARGS_((Tk_Canvas canvas, 103 Tk_Item *itemPtr, double *rectPtr)); 104static int WinItemToPostscript _ANSI_ARGS_((Tcl_Interp *interp, 105 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); 106static double WinItemToPoint _ANSI_ARGS_((Tk_Canvas canvas, 107 Tk_Item *itemPtr, double *pointPtr)); 108#ifdef X_GetImage 109static int xerrorhandler _ANSI_ARGS_((ClientData clientData, 110 XErrorEvent *e)); 111#endif 112static int CanvasPsWindow _ANSI_ARGS_((Tcl_Interp *interp, 113 Tk_Window tkwin, Tk_Canvas canvas, double x, 114 double y, int width, int height)); 115 116/* 117 * The structure below defines the window item type by means of procedures 118 * that can be invoked by generic item code. 119 */ 120 121Tk_ItemType tkWindowType = { 122 "window", /* name */ 123 sizeof(WindowItem), /* itemSize */ 124 CreateWinItem, /* createProc */ 125 configSpecs, /* configSpecs */ 126 ConfigureWinItem, /* configureProc */ 127 WinItemCoords, /* coordProc */ 128 DeleteWinItem, /* deleteProc */ 129 DisplayWinItem, /* displayProc */ 130 1|TK_CONFIG_OBJS, /* flags */ 131 WinItemToPoint, /* pointProc */ 132 WinItemToArea, /* areaProc */ 133 WinItemToPostscript, /* postscriptProc */ 134 ScaleWinItem, /* scaleProc */ 135 TranslateWinItem, /* translateProc */ 136 (Tk_ItemIndexProc *) NULL, /* indexProc */ 137 (Tk_ItemCursorProc *) NULL, /* cursorProc */ 138 (Tk_ItemSelectionProc *) NULL, /* selectionProc */ 139 (Tk_ItemInsertProc *) NULL, /* insertProc */ 140 (Tk_ItemDCharsProc *) NULL, /* dTextProc */ 141 (Tk_ItemType *) NULL, /* nextPtr */ 142}; 143 144 145/* 146 * The structure below defines the official type record for the 147 * placer: 148 */ 149 150static Tk_GeomMgr canvasGeomType = { 151 "canvas", /* name */ 152 WinItemRequestProc, /* requestProc */ 153 WinItemLostSlaveProc, /* lostSlaveProc */ 154}; 155 156/* 157 *-------------------------------------------------------------- 158 * 159 * CreateWinItem -- 160 * 161 * This procedure is invoked to create a new window 162 * item in a canvas. 163 * 164 * Results: 165 * A standard Tcl return value. If an error occurred in 166 * creating the item, then an error message is left in 167 * the interp's result; in this case itemPtr is 168 * left uninitialized, so it can be safely freed by the 169 * caller. 170 * 171 * Side effects: 172 * A new window item is created. 173 * 174 *-------------------------------------------------------------- 175 */ 176 177static int 178CreateWinItem(interp, canvas, itemPtr, objc, objv) 179 Tcl_Interp *interp; /* Interpreter for error reporting. */ 180 Tk_Canvas canvas; /* Canvas to hold new item. */ 181 Tk_Item *itemPtr; /* Record to hold new item; header 182 * has been initialized by caller. */ 183 int objc; /* Number of arguments in objv. */ 184 Tcl_Obj *CONST objv[]; /* Arguments describing window. */ 185{ 186 WindowItem *winItemPtr = (WindowItem *) itemPtr; 187 int i; 188 189 if (objc == 0) { 190 panic("canvas did not pass any coords\n"); 191 } 192 193 /* 194 * Initialize item's record. 195 */ 196 197 winItemPtr->tkwin = NULL; 198 winItemPtr->width = 0; 199 winItemPtr->height = 0; 200 winItemPtr->anchor = TK_ANCHOR_CENTER; 201 winItemPtr->canvas = canvas; 202 203 /* 204 * Process the arguments to fill in the item record. 205 * Only 1 (list) or 2 (x y) coords are allowed. 206 */ 207 208 if (objc == 1) { 209 i = 1; 210 } else { 211 char *arg = Tcl_GetString(objv[1]); 212 i = 2; 213 if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { 214 i = 1; 215 } 216 } 217 if (WinItemCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { 218 goto error; 219 } 220 if (ConfigureWinItem(interp, canvas, itemPtr, objc-i, objv+i, 0) 221 == TCL_OK) { 222 return TCL_OK; 223 } 224 225 error: 226 DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 227 return TCL_ERROR; 228} 229 230/* 231 *-------------------------------------------------------------- 232 * 233 * WinItemCoords -- 234 * 235 * This procedure is invoked to process the "coords" widget 236 * command on window items. See the user documentation for 237 * details on what it does. 238 * 239 * Results: 240 * Returns TCL_OK or TCL_ERROR, and sets the interp's result. 241 * 242 * Side effects: 243 * The coordinates for the given item may be changed. 244 * 245 *-------------------------------------------------------------- 246 */ 247 248static int 249WinItemCoords(interp, canvas, itemPtr, objc, objv) 250 Tcl_Interp *interp; /* Used for error reporting. */ 251 Tk_Canvas canvas; /* Canvas containing item. */ 252 Tk_Item *itemPtr; /* Item whose coordinates are to be 253 * read or modified. */ 254 int objc; /* Number of coordinates supplied in 255 * objv. */ 256 Tcl_Obj *CONST objv[]; /* Array of coordinates: x1, y1, 257 * x2, y2, ... */ 258{ 259 WindowItem *winItemPtr = (WindowItem *) itemPtr; 260 261 if (objc == 0) { 262 Tcl_Obj *obj = Tcl_NewObj(); 263 Tcl_Obj *subobj = Tcl_NewDoubleObj(winItemPtr->x); 264 Tcl_ListObjAppendElement(interp, obj, subobj); 265 subobj = Tcl_NewDoubleObj(winItemPtr->y); 266 Tcl_ListObjAppendElement(interp, obj, subobj); 267 Tcl_SetObjResult(interp, obj); 268 } else if (objc < 3) { 269 if (objc==1) { 270 if (Tcl_ListObjGetElements(interp, objv[0], &objc, 271 (Tcl_Obj ***) &objv) != TCL_OK) { 272 return TCL_ERROR; 273 } else if (objc != 2) { 274 char buf[64 + TCL_INTEGER_SPACE]; 275 276 sprintf(buf, "wrong # coordinates: expected 2, got %d", objc); 277 Tcl_SetResult(interp, buf, TCL_VOLATILE); 278 return TCL_ERROR; 279 } 280 } 281 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], &winItemPtr->x) 282 != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1], 283 &winItemPtr->y) != TCL_OK)) { 284 return TCL_ERROR; 285 } 286 ComputeWindowBbox(canvas, winItemPtr); 287 } else { 288 char buf[64 + TCL_INTEGER_SPACE]; 289 290 sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc); 291 Tcl_SetResult(interp, buf, TCL_VOLATILE); 292 return TCL_ERROR; 293 } 294 return TCL_OK; 295} 296 297/* 298 *-------------------------------------------------------------- 299 * 300 * ConfigureWinItem -- 301 * 302 * This procedure is invoked to configure various aspects 303 * of a window item, such as its anchor position. 304 * 305 * Results: 306 * A standard Tcl result code. If an error occurs, then 307 * an error message is left in the interp's result. 308 * 309 * Side effects: 310 * Configuration information may be set for itemPtr. 311 * 312 *-------------------------------------------------------------- 313 */ 314 315static int 316ConfigureWinItem(interp, canvas, itemPtr, objc, objv, flags) 317 Tcl_Interp *interp; /* Used for error reporting. */ 318 Tk_Canvas canvas; /* Canvas containing itemPtr. */ 319 Tk_Item *itemPtr; /* Window item to reconfigure. */ 320 int objc; /* Number of elements in objv. */ 321 Tcl_Obj *CONST objv[]; /* Arguments describing things to configure. */ 322 int flags; /* Flags to pass to Tk_ConfigureWidget. */ 323{ 324 WindowItem *winItemPtr = (WindowItem *) itemPtr; 325 Tk_Window oldWindow; 326 Tk_Window canvasTkwin; 327 328 oldWindow = winItemPtr->tkwin; 329 canvasTkwin = Tk_CanvasTkwin(canvas); 330 if (TCL_OK != Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, objc, 331 (CONST char **) objv, (char *) winItemPtr, flags|TK_CONFIG_OBJS)) { 332 return TCL_ERROR; 333 } 334 335 /* 336 * A few of the options require additional processing. 337 */ 338 339 if (oldWindow != winItemPtr->tkwin) { 340 if (oldWindow != NULL) { 341 Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, 342 WinItemStructureProc, (ClientData) winItemPtr); 343 Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL, 344 (ClientData) NULL); 345 Tk_UnmaintainGeometry(oldWindow, canvasTkwin); 346 Tk_UnmapWindow(oldWindow); 347 } 348 if (winItemPtr->tkwin != NULL) { 349 Tk_Window ancestor, parent; 350 351 /* 352 * Make sure that the canvas is either the parent of the 353 * window associated with the item or a descendant of that 354 * parent. Also, don't allow a top-of-hierarchy window to be 355 * managed inside a canvas. 356 */ 357 358 parent = Tk_Parent(winItemPtr->tkwin); 359 for (ancestor = canvasTkwin; ; 360 ancestor = Tk_Parent(ancestor)) { 361 if (ancestor == parent) { 362 break; 363 } 364 if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_HIERARCHY) { 365 badWindow: 366 Tcl_AppendResult(interp, "can't use ", 367 Tk_PathName(winItemPtr->tkwin), 368 " in a window item of this canvas", (char *) NULL); 369 winItemPtr->tkwin = NULL; 370 return TCL_ERROR; 371 } 372 } 373 if (((Tk_FakeWin *) (winItemPtr->tkwin))->flags & TK_TOP_HIERARCHY) { 374 goto badWindow; 375 } 376 if (winItemPtr->tkwin == canvasTkwin) { 377 goto badWindow; 378 } 379 Tk_CreateEventHandler(winItemPtr->tkwin, StructureNotifyMask, 380 WinItemStructureProc, (ClientData) winItemPtr); 381 Tk_ManageGeometry(winItemPtr->tkwin, &canvasGeomType, 382 (ClientData) winItemPtr); 383 } 384 } 385 if ((winItemPtr->tkwin != NULL) 386 && (itemPtr->state == TK_STATE_HIDDEN)) { 387 if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { 388 Tk_UnmapWindow(winItemPtr->tkwin); 389 } else { 390 Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); 391 } 392 } 393 394 ComputeWindowBbox(canvas, winItemPtr); 395 396 return TCL_OK; 397} 398 399/* 400 *-------------------------------------------------------------- 401 * 402 * DeleteWinItem -- 403 * 404 * This procedure is called to clean up the data structure 405 * associated with a window item. 406 * 407 * Results: 408 * None. 409 * 410 * Side effects: 411 * Resources associated with itemPtr are released. 412 * 413 *-------------------------------------------------------------- 414 */ 415 416static void 417DeleteWinItem(canvas, itemPtr, display) 418 Tk_Canvas canvas; /* Overall info about widget. */ 419 Tk_Item *itemPtr; /* Item that is being deleted. */ 420 Display *display; /* Display containing window for 421 * canvas. */ 422{ 423 WindowItem *winItemPtr = (WindowItem *) itemPtr; 424 Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); 425 426 if (winItemPtr->tkwin != NULL) { 427 Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, 428 WinItemStructureProc, (ClientData) winItemPtr); 429 Tk_ManageGeometry(winItemPtr->tkwin, (Tk_GeomMgr *) NULL, 430 (ClientData) NULL); 431 if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { 432 Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); 433 } 434 Tk_UnmapWindow(winItemPtr->tkwin); 435 } 436} 437 438/* 439 *-------------------------------------------------------------- 440 * 441 * ComputeWindowBbox -- 442 * 443 * This procedure is invoked to compute the bounding box of 444 * all the pixels that may be drawn as part of a window item. 445 * This procedure is where the child window's placement is 446 * computed. 447 * 448 * Results: 449 * None. 450 * 451 * Side effects: 452 * The fields x1, y1, x2, and y2 are updated in the header 453 * for itemPtr. 454 * 455 *-------------------------------------------------------------- 456 */ 457 458static void 459ComputeWindowBbox(canvas, winItemPtr) 460 Tk_Canvas canvas; /* Canvas that contains item. */ 461 WindowItem *winItemPtr; /* Item whose bbox is to be 462 * recomputed. */ 463{ 464 int width, height, x, y; 465 Tk_State state = winItemPtr->header.state; 466 467 x = (int) (winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5)); 468 y = (int) (winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5)); 469 470 if (state == TK_STATE_NULL) { 471 state = ((TkCanvas *)canvas)->canvas_state; 472 } 473 if ((winItemPtr->tkwin == NULL) || (state == TK_STATE_HIDDEN)) { 474 /* 475 * There is no window for this item yet. Just give it a 1x1 476 * bounding box. Don't give it a 0x0 bounding box; there are 477 * strange cases where this bounding box might be used as the 478 * dimensions of the window, and 0x0 causes problems under X. 479 */ 480 481 winItemPtr->header.x1 = x; 482 winItemPtr->header.x2 = winItemPtr->header.x1 + 1; 483 winItemPtr->header.y1 = y; 484 winItemPtr->header.y2 = winItemPtr->header.y1 + 1; 485 return; 486 } 487 488 /* 489 * Compute dimensions of window. 490 */ 491 492 width = winItemPtr->width; 493 if (width <= 0) { 494 width = Tk_ReqWidth(winItemPtr->tkwin); 495 if (width <= 0) { 496 width = 1; 497 } 498 } 499 height = winItemPtr->height; 500 if (height <= 0) { 501 height = Tk_ReqHeight(winItemPtr->tkwin); 502 if (height <= 0) { 503 height = 1; 504 } 505 } 506 507 /* 508 * Compute location of window, using anchor information. 509 */ 510 511 switch (winItemPtr->anchor) { 512 case TK_ANCHOR_N: 513 x -= width/2; 514 break; 515 case TK_ANCHOR_NE: 516 x -= width; 517 break; 518 case TK_ANCHOR_E: 519 x -= width; 520 y -= height/2; 521 break; 522 case TK_ANCHOR_SE: 523 x -= width; 524 y -= height; 525 break; 526 case TK_ANCHOR_S: 527 x -= width/2; 528 y -= height; 529 break; 530 case TK_ANCHOR_SW: 531 y -= height; 532 break; 533 case TK_ANCHOR_W: 534 y -= height/2; 535 break; 536 case TK_ANCHOR_NW: 537 break; 538 case TK_ANCHOR_CENTER: 539 x -= width/2; 540 y -= height/2; 541 break; 542 } 543 544 /* 545 * Store the information in the item header. 546 */ 547 548 winItemPtr->header.x1 = x; 549 winItemPtr->header.y1 = y; 550 winItemPtr->header.x2 = x + width; 551 winItemPtr->header.y2 = y + height; 552} 553 554/* 555 *-------------------------------------------------------------- 556 * 557 * DisplayWinItem -- 558 * 559 * This procedure is invoked to "draw" a window item in a given 560 * drawable. Since the window draws itself, we needn't do any 561 * actual redisplay here. However, this procedure takes care 562 * of actually repositioning the child window so that it occupies 563 * the correct screen position. 564 * 565 * Results: 566 * None. 567 * 568 * Side effects: 569 * The child window's position may get changed. Note: this 570 * procedure gets called both when a window needs to be displayed 571 * and when it ceases to be visible on the screen (e.g. it was 572 * scrolled or moved off-screen or the enclosing canvas is 573 * unmapped). 574 * 575 *-------------------------------------------------------------- 576 */ 577 578static void 579DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, 580 regionWidth, regionHeight) 581 Tk_Canvas canvas; /* Canvas that contains item. */ 582 Tk_Item *itemPtr; /* Item to be displayed. */ 583 Display *display; /* Display on which to draw item. */ 584 Drawable drawable; /* Pixmap or window in which to draw 585 * item. */ 586 int regionX, regionY, regionWidth, regionHeight; 587 /* Describes region of canvas that 588 * must be redisplayed (not used). */ 589{ 590 WindowItem *winItemPtr = (WindowItem *) itemPtr; 591 int width, height; 592 short x, y; 593 Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); 594 Tk_State state = itemPtr->state; 595 596 if (winItemPtr->tkwin == NULL) { 597 return; 598 } 599 if (state == TK_STATE_NULL) { 600 state = ((TkCanvas *)canvas)->canvas_state; 601 } 602 603 /* 604 * A drawable of None is used by the canvas UnmapNotify handler 605 * to indicate that we should no longer display ourselves. 606 */ 607 if (state == TK_STATE_HIDDEN || drawable == None) { 608 if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { 609 Tk_UnmapWindow(winItemPtr->tkwin); 610 } else { 611 Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); 612 } 613 return; 614 } 615 Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1, 616 (double) winItemPtr->header.y1, &x, &y); 617 width = winItemPtr->header.x2 - winItemPtr->header.x1; 618 height = winItemPtr->header.y2 - winItemPtr->header.y1; 619 620 /* 621 * If the window is completely out of the visible area of the canvas 622 * then unmap it. This code used not to be present (why unmap the 623 * window if it isn't visible anyway?) but this could cause the 624 * window to suddenly reappear if the canvas window got resized. 625 */ 626 627 if (((x + width) <= 0) || ((y + height) <= 0) 628 || (x >= Tk_Width(canvasTkwin)) || (y >= Tk_Height(canvasTkwin))) { 629 if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { 630 Tk_UnmapWindow(winItemPtr->tkwin); 631 } else { 632 Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); 633 } 634 return; 635 } 636 637 /* 638 * Reposition and map the window (but in different ways depending 639 * on whether the canvas is the window's parent). 640 */ 641 642 if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { 643 if ((x != Tk_X(winItemPtr->tkwin)) || (y != Tk_Y(winItemPtr->tkwin)) 644 || (width != Tk_Width(winItemPtr->tkwin)) 645 || (height != Tk_Height(winItemPtr->tkwin))) { 646 Tk_MoveResizeWindow(winItemPtr->tkwin, x, y, width, height); 647 } 648 Tk_MapWindow(winItemPtr->tkwin); 649 } else { 650 Tk_MaintainGeometry(winItemPtr->tkwin, canvasTkwin, x, y, 651 width, height); 652 } 653} 654 655/* 656 *-------------------------------------------------------------- 657 * 658 * WinItemToPoint -- 659 * 660 * Computes the distance from a given point to a given 661 * window, in canvas units. 662 * 663 * Results: 664 * The return value is 0 if the point whose x and y coordinates 665 * are coordPtr[0] and coordPtr[1] is inside the window. If the 666 * point isn't inside the window then the return value is the 667 * distance from the point to the window. 668 * 669 * Side effects: 670 * None. 671 * 672 *-------------------------------------------------------------- 673 */ 674 675static double 676WinItemToPoint(canvas, itemPtr, pointPtr) 677 Tk_Canvas canvas; /* Canvas containing item. */ 678 Tk_Item *itemPtr; /* Item to check against point. */ 679 double *pointPtr; /* Pointer to x and y coordinates. */ 680{ 681 WindowItem *winItemPtr = (WindowItem *) itemPtr; 682 double x1, x2, y1, y2, xDiff, yDiff; 683 684 x1 = winItemPtr->header.x1; 685 y1 = winItemPtr->header.y1; 686 x2 = winItemPtr->header.x2; 687 y2 = winItemPtr->header.y2; 688 689 /* 690 * Point is outside window. 691 */ 692 693 if (pointPtr[0] < x1) { 694 xDiff = x1 - pointPtr[0]; 695 } else if (pointPtr[0] >= x2) { 696 xDiff = pointPtr[0] + 1 - x2; 697 } else { 698 xDiff = 0; 699 } 700 701 if (pointPtr[1] < y1) { 702 yDiff = y1 - pointPtr[1]; 703 } else if (pointPtr[1] >= y2) { 704 yDiff = pointPtr[1] + 1 - y2; 705 } else { 706 yDiff = 0; 707 } 708 709 return hypot(xDiff, yDiff); 710} 711 712/* 713 *-------------------------------------------------------------- 714 * 715 * WinItemToArea -- 716 * 717 * This procedure is called to determine whether an item 718 * lies entirely inside, entirely outside, or overlapping 719 * a given rectangle. 720 * 721 * Results: 722 * -1 is returned if the item is entirely outside the area 723 * given by rectPtr, 0 if it overlaps, and 1 if it is entirely 724 * inside the given area. 725 * 726 * Side effects: 727 * None. 728 * 729 *-------------------------------------------------------------- 730 */ 731 732static int 733WinItemToArea(canvas, itemPtr, rectPtr) 734 Tk_Canvas canvas; /* Canvas containing item. */ 735 Tk_Item *itemPtr; /* Item to check against rectangle. */ 736 double *rectPtr; /* Pointer to array of four coordinates 737 * (x1, y1, x2, y2) describing rectangular 738 * area. */ 739{ 740 WindowItem *winItemPtr = (WindowItem *) itemPtr; 741 742 if ((rectPtr[2] <= winItemPtr->header.x1) 743 || (rectPtr[0] >= winItemPtr->header.x2) 744 || (rectPtr[3] <= winItemPtr->header.y1) 745 || (rectPtr[1] >= winItemPtr->header.y2)) { 746 return -1; 747 } 748 if ((rectPtr[0] <= winItemPtr->header.x1) 749 && (rectPtr[1] <= winItemPtr->header.y1) 750 && (rectPtr[2] >= winItemPtr->header.x2) 751 && (rectPtr[3] >= winItemPtr->header.y2)) { 752 return 1; 753 } 754 return 0; 755} 756 757/* 758 *-------------------------------------------------------------- 759 * 760 * xerrorhandler -- 761 * 762 * This is a dummy function to catch X11 errors during an 763 * attempt to print a canvas window. 764 * 765 * Results: 766 * None. 767 * 768 * Side effects: 769 * None. 770 * 771 *-------------------------------------------------------------- 772 */ 773 774#ifdef X_GetImage 775static int 776xerrorhandler(clientData, e) 777 ClientData clientData; 778 XErrorEvent *e; 779{ 780 return 0; 781} 782#endif 783 784 785/* 786 *-------------------------------------------------------------- 787 * 788 * WinItemToPostscript -- 789 * 790 * This procedure is called to generate Postscript for 791 * window items. 792 * 793 * Results: 794 * The return value is a standard Tcl result. If an error 795 * occurs in generating Postscript then an error message is 796 * left in interp->result, replacing whatever used to be there. 797 * If no error occurs, then Postscript for the item is appended 798 * to the result. 799 * 800 * Side effects: 801 * None. 802 * 803 *-------------------------------------------------------------- 804 */ 805 806static int 807WinItemToPostscript(interp, canvas, itemPtr, prepass) 808 Tcl_Interp *interp; /* Leave Postscript or error message 809 * here. */ 810 Tk_Canvas canvas; /* Information about overall canvas. */ 811 Tk_Item *itemPtr; /* Item for which Postscript is 812 * wanted. */ 813 int prepass; /* 1 means this is a prepass to 814 * collect font information; 0 means 815 * final Postscript is being created.*/ 816{ 817 WindowItem *winItemPtr = (WindowItem *)itemPtr; 818 819 double x, y; 820 int width, height; 821 Tk_Window tkwin = winItemPtr->tkwin; 822 823 if (prepass || winItemPtr->tkwin == NULL) { 824 return TCL_OK; 825 } 826 827 width = Tk_Width(tkwin); 828 height = Tk_Height(tkwin); 829 830 /* 831 * Compute the coordinates of the lower-left corner of the window, 832 * taking into account the anchor position for the window. 833 */ 834 835 x = winItemPtr->x; 836 y = Tk_CanvasPsY(canvas, winItemPtr->y); 837 838 switch (winItemPtr->anchor) { 839 case TK_ANCHOR_NW: y -= height; break; 840 case TK_ANCHOR_N: x -= width/2.0; y -= height; break; 841 case TK_ANCHOR_NE: x -= width; y -= height; break; 842 case TK_ANCHOR_E: x -= width; y -= height/2.0; break; 843 case TK_ANCHOR_SE: x -= width; break; 844 case TK_ANCHOR_S: x -= width/2.0; break; 845 case TK_ANCHOR_SW: break; 846 case TK_ANCHOR_W: y -= height/2.0; break; 847 case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; 848 } 849 850 return CanvasPsWindow(interp, tkwin, canvas, x, y, width, height); 851} 852 853static int 854CanvasPsWindow(interp, tkwin, canvas, x, y, width, height) 855 Tcl_Interp *interp; /* Leave Postscript or error message 856 * here. */ 857 Tk_Window tkwin; /* window to be printed */ 858 Tk_Canvas canvas; /* Information about overall canvas. */ 859 double x, y; /* origin of window. */ 860 int width, height; /* width/height of window. */ 861{ 862 char buffer[256]; 863 XImage *ximage; 864 int result; 865 Tcl_DString buffer1, buffer2; 866#ifdef X_GetImage 867 Tk_ErrorHandler handle; 868#endif 869 870 sprintf(buffer, "\n%%%% %s item (%s, %d x %d)\n%.15g %.15g translate\n", 871 Tk_Class(tkwin), Tk_PathName(tkwin), width, height, x, y); 872 Tcl_AppendResult(interp, buffer, (char *) NULL); 873 874 /* first try if the widget has its own "postscript" command. If it 875 * exists, this will produce much better postscript than 876 * when a pixmap is used. 877 */ 878 879 Tcl_DStringInit(&buffer1); 880 Tcl_DStringInit(&buffer2); 881 Tcl_DStringGetResult(interp, &buffer2); 882 sprintf (buffer, "%s postscript -prolog 0\n", Tk_PathName(tkwin)); 883 result = Tcl_Eval(interp, buffer); 884 Tcl_DStringGetResult(interp, &buffer1); 885 Tcl_DStringResult(interp, &buffer2); 886 Tcl_DStringFree(&buffer2); 887 888 if (result == TCL_OK) { 889 Tcl_AppendResult(interp, 890 "50 dict begin\nsave\ngsave\n", 891 (char *) NULL); 892 sprintf (buffer, 893 "0 %d moveto %d 0 rlineto 0 -%d rlineto -%d", 894 height, width, height, width); 895 Tcl_AppendResult(interp, buffer, (char *) NULL); 896 Tcl_AppendResult(interp, " 0 rlineto closepath\n", 897 "1.000 1.000 1.000 setrgbcolor AdjustColor\nfill\ngrestore\n", 898 Tcl_DStringValue(&buffer1), "\nrestore\nend\n\n\n", 899 (char *) NULL); 900 Tcl_DStringFree(&buffer1); 901 902 return result; 903 } 904 Tcl_DStringFree(&buffer1); 905 906 /* 907 * If the window is off the screen it will generate an BadMatch/XError 908 * We catch any BadMatch errors here 909 */ 910#ifdef X_GetImage 911 handle = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, 912 X_GetImage, -1, xerrorhandler, (ClientData) tkwin); 913#endif 914 915 /* 916 * Generate an XImage from the window. We can then read pixel 917 * values out of the XImage. 918 */ 919 920 ximage = XGetImage(Tk_Display(tkwin), Tk_WindowId(tkwin), 0, 0, 921 (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); 922 923#ifdef X_GetImage 924 Tk_DeleteErrorHandler(handle); 925#endif 926 927 if (ximage == (XImage*) NULL) { 928 return TCL_OK; 929 } 930 931 result = TkPostscriptImage(interp, tkwin, 932 ((TkCanvas *)canvas)->psInfo, ximage, 0, 0, width, height); 933 934 XDestroyImage(ximage); 935 return result; 936} 937 938/* 939 *-------------------------------------------------------------- 940 * 941 * ScaleWinItem -- 942 * 943 * This procedure is invoked to rescale a window item. 944 * 945 * Results: 946 * None. 947 * 948 * Side effects: 949 * The window referred to by itemPtr is rescaled 950 * so that the following transformation is applied to all 951 * point coordinates: 952 * x' = originX + scaleX*(x-originX) 953 * y' = originY + scaleY*(y-originY) 954 * 955 *-------------------------------------------------------------- 956 */ 957 958static void 959ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) 960 Tk_Canvas canvas; /* Canvas containing window. */ 961 Tk_Item *itemPtr; /* Window to be scaled. */ 962 double originX, originY; /* Origin about which to scale window. */ 963 double scaleX; /* Amount to scale in X direction. */ 964 double scaleY; /* Amount to scale in Y direction. */ 965{ 966 WindowItem *winItemPtr = (WindowItem *) itemPtr; 967 968 winItemPtr->x = originX + scaleX*(winItemPtr->x - originX); 969 winItemPtr->y = originY + scaleY*(winItemPtr->y - originY); 970 if (winItemPtr->width > 0) { 971 winItemPtr->width = (int) (scaleX*winItemPtr->width); 972 } 973 if (winItemPtr->height > 0) { 974 winItemPtr->height = (int) (scaleY*winItemPtr->height); 975 } 976 ComputeWindowBbox(canvas, winItemPtr); 977} 978 979/* 980 *-------------------------------------------------------------- 981 * 982 * TranslateWinItem -- 983 * 984 * This procedure is called to move a window by a given amount. 985 * 986 * Results: 987 * None. 988 * 989 * Side effects: 990 * The position of the window is offset by (xDelta, yDelta), 991 * and the bounding box is updated in the generic part of the 992 * item structure. 993 * 994 *-------------------------------------------------------------- 995 */ 996 997static void 998TranslateWinItem(canvas, itemPtr, deltaX, deltaY) 999 Tk_Canvas canvas; /* Canvas containing item. */ 1000 Tk_Item *itemPtr; /* Item that is being moved. */ 1001 double deltaX, deltaY; /* Amount by which item is to be 1002 * moved. */ 1003{ 1004 WindowItem *winItemPtr = (WindowItem *) itemPtr; 1005 1006 winItemPtr->x += deltaX; 1007 winItemPtr->y += deltaY; 1008 ComputeWindowBbox(canvas, winItemPtr); 1009} 1010 1011/* 1012 *-------------------------------------------------------------- 1013 * 1014 * WinItemStructureProc -- 1015 * 1016 * This procedure is invoked whenever StructureNotify events 1017 * occur for a window that's managed as part of a canvas window 1018 * item. This procudure's only purpose is to clean up when 1019 * windows are deleted. 1020 * 1021 * Results: 1022 * None. 1023 * 1024 * Side effects: 1025 * The window is disassociated from the window item when it is 1026 * deleted. 1027 * 1028 *-------------------------------------------------------------- 1029 */ 1030 1031static void 1032WinItemStructureProc(clientData, eventPtr) 1033 ClientData clientData; /* Pointer to record describing window item. */ 1034 XEvent *eventPtr; /* Describes what just happened. */ 1035{ 1036 WindowItem *winItemPtr = (WindowItem *) clientData; 1037 1038 if (eventPtr->type == DestroyNotify) { 1039 winItemPtr->tkwin = NULL; 1040 } 1041} 1042 1043/* 1044 *-------------------------------------------------------------- 1045 * 1046 * WinItemRequestProc -- 1047 * 1048 * This procedure is invoked whenever a window that's associated 1049 * with a window canvas item changes its requested dimensions. 1050 * 1051 * Results: 1052 * None. 1053 * 1054 * Side effects: 1055 * The size and location on the screen of the window may change, 1056 * depending on the options specified for the window item. 1057 * 1058 *-------------------------------------------------------------- 1059 */ 1060 1061static void 1062WinItemRequestProc(clientData, tkwin) 1063 ClientData clientData; /* Pointer to record for window item. */ 1064 Tk_Window tkwin; /* Window that changed its desired 1065 * size. */ 1066{ 1067 WindowItem *winItemPtr = (WindowItem *) clientData; 1068 1069 ComputeWindowBbox(winItemPtr->canvas, winItemPtr); 1070 1071 /* 1072 * A drawable argument of None to DisplayWinItem is used by the canvas 1073 * UnmapNotify handler to indicate that we should no longer display 1074 * ourselves, so need to pass a (bogus) non-zero drawable value here. 1075 */ 1076 DisplayWinItem(winItemPtr->canvas, (Tk_Item *) winItemPtr, NULL, 1077 (Drawable) -1, 0, 0, 0, 0); 1078} 1079 1080/* 1081 *-------------------------------------------------------------- 1082 * 1083 * WinItemLostSlaveProc -- 1084 * 1085 * This procedure is invoked by Tk whenever some other geometry 1086 * claims control over a slave that used to be managed by us. 1087 * 1088 * Results: 1089 * None. 1090 * 1091 * Side effects: 1092 * Forgets all canvas-related information about the slave. 1093 * 1094 *-------------------------------------------------------------- 1095 */ 1096 1097 /* ARGSUSED */ 1098static void 1099WinItemLostSlaveProc(clientData, tkwin) 1100 ClientData clientData; /* WindowItem structure for slave window that 1101 * was stolen away. */ 1102 Tk_Window tkwin; /* Tk's handle for the slave window. */ 1103{ 1104 WindowItem *winItemPtr = (WindowItem *) clientData; 1105 Tk_Window canvasTkwin = Tk_CanvasTkwin(winItemPtr->canvas); 1106 1107 Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, 1108 WinItemStructureProc, (ClientData) winItemPtr); 1109 if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { 1110 Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); 1111 } 1112 Tk_UnmapWindow(winItemPtr->tkwin); 1113 winItemPtr->tkwin = NULL; 1114} 1115