1/* 2 * tkTableWin.c -- 3 * 4 * This module implements embedded windows for table widgets. 5 * Much of this code is adapted from tkGrid.c and tkTextWind.c. 6 * 7 * Copyright (c) 1998-2002 Jeffrey Hobbs 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: tkTableWin.c,v 1.6 2004/06/11 00:24:44 hobbs Exp $ 13 */ 14 15#include "tkTable.h" 16 17static int StickyParseProc _ANSI_ARGS_((ClientData clientData, 18 Tcl_Interp *interp, Tk_Window tkwin, 19 CONST84 char *value, char *widgRec, int offset)); 20static char * StickyPrintProc _ANSI_ARGS_((ClientData clientData, 21 Tk_Window tkwin, char *widgRec, int offset, 22 Tcl_FreeProc **freeProcPtr)); 23 24static void EmbWinLostSlaveProc _ANSI_ARGS_((ClientData clientData, 25 Tk_Window tkwin)); 26static void EmbWinRequestProc _ANSI_ARGS_((ClientData clientData, 27 Tk_Window tkwin)); 28 29static void EmbWinCleanup _ANSI_ARGS_((Table *tablePtr, 30 TableEmbWindow *ewPtr)); 31static int EmbWinConfigure _ANSI_ARGS_((Table *tablePtr, 32 TableEmbWindow *ewPtr, 33 int objc, Tcl_Obj *CONST objv[])); 34static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData, 35 XEvent *eventPtr)); 36static void EmbWinUnmapNow _ANSI_ARGS_((Tk_Window ewTkwin, 37 Tk_Window tkwin)); 38 39static Tk_GeomMgr tableGeomType = { 40 "table", /* name */ 41 EmbWinRequestProc, /* requestProc */ 42 EmbWinLostSlaveProc, /* lostSlaveProc */ 43}; 44 45/* windows subcommands */ 46static CONST84 char *winCmdNames[] = { 47 "cget", "configure", "delete", "move", "names", (char *) NULL 48}; 49enum winCommand { 50 WIN_CGET, WIN_CONFIGURE, WIN_DELETE, WIN_MOVE, WIN_NAMES 51}; 52 53/* Flag values for "sticky"ness The 16 combinations subsume the packer's 54 * notion of anchor and fill. 55 * 56 * STICK_NORTH This window sticks to the top of its cavity. 57 * STICK_EAST This window sticks to the right edge of its cavity. 58 * STICK_SOUTH This window sticks to the bottom of its cavity. 59 * STICK_WEST This window sticks to the left edge of its cavity. 60 */ 61 62#define STICK_NORTH (1<<0) 63#define STICK_EAST (1<<1) 64#define STICK_SOUTH (1<<2) 65#define STICK_WEST (1<<3) 66 67/* 68 * The default specification for configuring embedded windows 69 * Done like this to make the command line parsing easy 70 */ 71 72static Tk_CustomOption stickyOption = { StickyParseProc, StickyPrintProc, 73 (ClientData) NULL }; 74static Tk_CustomOption tagBdOpt = { TableOptionBdSet, TableOptionBdGet, 75 (ClientData) BD_TABLE_WIN }; 76 77static Tk_ConfigSpec winConfigSpecs[] = { 78 {TK_CONFIG_BORDER, "-background", "background", "Background", NULL, 79 Tk_Offset(TableEmbWindow, bg), 80 TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, 81 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0}, 82 {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, 83 {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", "", 84 0 /* no offset */, 85 TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK, &tagBdOpt }, 86 {TK_CONFIG_STRING, "-create", (char *)NULL, (char *)NULL, (char *)NULL, 87 Tk_Offset(TableEmbWindow, create), 88 TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, 89 {TK_CONFIG_PIXELS, "-padx", (char *)NULL, (char *)NULL, (char *)NULL, 90 Tk_Offset(TableEmbWindow, padX), TK_CONFIG_DONT_SET_DEFAULT }, 91 {TK_CONFIG_PIXELS, "-pady", (char *)NULL, (char *)NULL, (char *)NULL, 92 Tk_Offset(TableEmbWindow, padY), TK_CONFIG_DONT_SET_DEFAULT }, 93 {TK_CONFIG_CUSTOM, "-sticky", (char *)NULL, (char *)NULL, (char *)NULL, 94 Tk_Offset(TableEmbWindow, sticky), TK_CONFIG_DONT_SET_DEFAULT, 95 &stickyOption}, 96 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", NULL, 97 Tk_Offset(TableEmbWindow, relief), 0 }, 98 {TK_CONFIG_WINDOW, "-window", (char *)NULL, (char *)NULL, (char *)NULL, 99 Tk_Offset(TableEmbWindow, tkwin), 100 TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, 101 {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, 102 (char *)NULL, 0, 0 } 103}; 104 105/* 106 *---------------------------------------------------------------------- 107 * 108 * StickyPrintProc -- 109 * Converts the internal boolean combination of "sticky" bits onto 110 * a TCL string element containing zero or more of n, s, e, or w. 111 * 112 * Results: 113 * A string is placed into the "result" pointer. 114 * 115 * Side effects: 116 * none. 117 * 118 *---------------------------------------------------------------------- 119 */ 120static char * 121StickyPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) 122 ClientData clientData; /* Ignored. */ 123 Tk_Window tkwin; /* Window for text widget. */ 124 char *widgRec; /* Pointer to TkTextEmbWindow 125 * structure. */ 126 int offset; /* Ignored. */ 127 Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with 128 * information about how to reclaim 129 * storage for return string. */ 130{ 131 int flags = ((TableEmbWindow *) widgRec)->sticky; 132 int count = 0; 133 char *result = (char *) ckalloc(5*sizeof(char)); 134 135 if (flags&STICK_NORTH) result[count++] = 'n'; 136 if (flags&STICK_EAST) result[count++] = 'e'; 137 if (flags&STICK_SOUTH) result[count++] = 's'; 138 if (flags&STICK_WEST) result[count++] = 'w'; 139 140 *freeProcPtr = TCL_DYNAMIC; 141 result[count] = '\0'; 142 return result; 143} 144 145/* 146 *---------------------------------------------------------------------- 147 * 148 * StringParseProc -- 149 * Converts an ascii string representing a widgets stickyness 150 * into the boolean result. 151 * 152 * Results: 153 * The boolean combination of the "sticky" bits is retuned. If an 154 * error occurs, such as an invalid character, -1 is returned instead. 155 * 156 * Side effects: 157 * none 158 * 159 *---------------------------------------------------------------------- 160 */ 161static int 162StickyParseProc(clientData, interp, tkwin, value, widgRec, offset) 163 ClientData clientData; /* Not used.*/ 164 Tcl_Interp *interp; /* Used for reporting errors. */ 165 Tk_Window tkwin; /* Window for text widget. */ 166 CONST84 char *value; /* Value of option. */ 167 char *widgRec; /* Pointer to TkTextEmbWindow 168 * structure. */ 169 int offset; /* Offset into item (ignored). */ 170{ 171 register TableEmbWindow *ewPtr = (TableEmbWindow *) widgRec; 172 int sticky = 0; 173 char c; 174 175 while ((c = *value++) != '\0') { 176 switch (c) { 177 case 'n': case 'N': sticky |= STICK_NORTH; break; 178 case 'e': case 'E': sticky |= STICK_EAST; break; 179 case 's': case 'S': sticky |= STICK_SOUTH; break; 180 case 'w': case 'W': sticky |= STICK_WEST; break; 181 case ' ': case ',': case '\t': case '\r': case '\n': break; 182 default: 183 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), 184 "bad sticky value \"", --value, 185 "\": must contain n, s, e or w", 186 (char *) NULL); 187 return TCL_ERROR; 188 } 189 } 190 ewPtr->sticky = sticky; 191 return TCL_OK; 192} 193 194/* 195 * ckallocs space for a new embedded window structure and clears the structure 196 * returns the pointer to the new structure 197 */ 198static TableEmbWindow * 199TableNewEmbWindow(Table *tablePtr) 200{ 201 TableEmbWindow *ewPtr = (TableEmbWindow *) ckalloc(sizeof(TableEmbWindow)); 202 memset((VOID *) ewPtr, 0, sizeof(TableEmbWindow)); 203 204 /* 205 * Set the values that aren't 0/NULL by default 206 */ 207 ewPtr->tablePtr = tablePtr; 208 ewPtr->relief = -1; 209 ewPtr->padX = -1; 210 ewPtr->padY = -1; 211 212 return ewPtr; 213} 214 215/* 216 *---------------------------------------------------------------------- 217 * 218 * EmbWinCleanup -- 219 * Releases resources used by an embedded window before it is freed up. 220 * 221 * Results: 222 * Window will no longer be valid. 223 * 224 * Side effects: 225 * None. 226 * 227 *---------------------------------------------------------------------- 228 */ 229static void 230EmbWinCleanup(Table *tablePtr, TableEmbWindow *ewPtr) 231{ 232 Tk_FreeOptions(winConfigSpecs, (char *) ewPtr, tablePtr->display, 0); 233} 234 235/* 236 *-------------------------------------------------------------- 237 * 238 * EmbWinDisplay -- 239 * 240 * This procedure is invoked by TableDisplay for 241 * mapping windows into cells. 242 * 243 * Results: 244 * Displays or moves window on table screen. 245 * 246 * Side effects: 247 * None. 248 * 249 *-------------------------------------------------------------- 250 */ 251void 252EmbWinDisplay(Table *tablePtr, Drawable window, TableEmbWindow *ewPtr, 253 TableTag *tagPtr, int x, int y, int width, int height) 254{ 255 Tk_Window tkwin = tablePtr->tkwin; 256 Tk_Window ewTkwin = ewPtr->tkwin; 257 int diffx=0; /* Cavity width - slave width. */ 258 int diffy=0; /* Cavity hight - slave height. */ 259 int sticky = ewPtr->sticky; 260 int padx, pady; 261 262 if (ewPtr->bg) tagPtr->bg = ewPtr->bg; 263 if (ewPtr->relief != -1) tagPtr->relief = ewPtr->relief; 264 if (ewPtr->borders) { 265 tagPtr->borderStr = ewPtr->borderStr; 266 tagPtr->borders = ewPtr->borders; 267 tagPtr->bd[0] = ewPtr->bd[0]; 268 tagPtr->bd[1] = ewPtr->bd[1]; 269 tagPtr->bd[2] = ewPtr->bd[2]; 270 tagPtr->bd[3] = ewPtr->bd[3]; 271 } 272 273 padx = (ewPtr->padX < 0) ? tablePtr->padX : ewPtr->padX; 274 pady = (ewPtr->padY < 0) ? tablePtr->padY : ewPtr->padY; 275 276 x += padx; 277 width -= padx*2; 278 y += pady; 279 height -= pady*2; 280 281 if (width > Tk_ReqWidth(ewPtr->tkwin)) { 282 diffx = width - Tk_ReqWidth(ewPtr->tkwin); 283 width = Tk_ReqWidth(ewPtr->tkwin); 284 } 285 if (height > Tk_ReqHeight(ewPtr->tkwin)) { 286 diffy = height - Tk_ReqHeight(ewPtr->tkwin); 287 height = Tk_ReqHeight(ewPtr->tkwin); 288 } 289 if (sticky&STICK_EAST && sticky&STICK_WEST) { 290 width += diffx; 291 } 292 if (sticky&STICK_NORTH && sticky&STICK_SOUTH) { 293 height += diffy; 294 } 295 if (!(sticky&STICK_WEST)) { 296 x += (sticky&STICK_EAST) ? diffx : diffx/2; 297 } 298 if (!(sticky&STICK_NORTH)) { 299 y += (sticky&STICK_SOUTH) ? diffy : diffy/2; 300 } 301 302 /* 303 * If we fall below a specific minimum width/height requirement, 304 * we just unmap the window 305 */ 306 if (width < 2 || height < 2) { 307 if (ewPtr->displayed) { 308 EmbWinUnmapNow(ewTkwin, tkwin); 309 } 310 return; 311 } 312 313 if (tkwin == Tk_Parent(ewTkwin)) { 314 if ((x != Tk_X(ewTkwin)) || (y != Tk_Y(ewTkwin)) 315 || (width != Tk_Width(ewTkwin)) 316 || (height != Tk_Height(ewTkwin))) { 317 Tk_MoveResizeWindow(ewTkwin, x, y, width, height); 318 } 319 Tk_MapWindow(ewTkwin); 320 } else { 321 Tk_MaintainGeometry(ewTkwin, tkwin, x, y, width, height); 322 } 323 ewPtr->displayed = 1; 324} 325 326/* 327 *-------------------------------------------------------------- 328 * 329 * EmbWinUnmapNow -- 330 * Handles unmapping the window depending on parent. 331 * tkwin should be tablePtr->tkwin. 332 * ewTkwin should be ewPtr->tkwin. 333 * 334 * Results: 335 * Removes the window. 336 * 337 * Side effects: 338 * None. 339 * 340 *-------------------------------------------------------------- 341 */ 342static void 343EmbWinUnmapNow(Tk_Window ewTkwin, Tk_Window tkwin) 344{ 345 if (tkwin != Tk_Parent(ewTkwin)) { 346 Tk_UnmaintainGeometry(ewTkwin, tkwin); 347 } 348 Tk_UnmapWindow(ewTkwin); 349} 350 351/* 352 *-------------------------------------------------------------- 353 * 354 * EmbWinUnmap -- 355 * This procedure is invoked by TableAdjustParams for 356 * unmapping windows managed moved offscreen. 357 * rlo, ... should be in real coords. 358 * 359 * Results: 360 * None. 361 * 362 * Side effects: 363 * Unmaps embedded windows. 364 * 365 *-------------------------------------------------------------- 366 */ 367void 368EmbWinUnmap(Table *tablePtr, int rlo, int rhi, int clo, int chi) 369{ 370 register TableEmbWindow *ewPtr; 371 Tcl_HashEntry *entryPtr; 372 int row, col, trow, tcol; 373 char buf[INDEX_BUFSIZE]; 374 375 /* 376 * Transform numbers from real to user user coords 377 */ 378 rlo += tablePtr->rowOffset; 379 rhi += tablePtr->rowOffset; 380 clo += tablePtr->colOffset; 381 chi += tablePtr->colOffset; 382 for (row = rlo; row <= rhi; row++) { 383 for (col = clo; col <= chi; col++) { 384 TableTrueCell(tablePtr, row, col, &trow, &tcol); 385 TableMakeArrayIndex(trow, tcol, buf); 386 entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf); 387 if (entryPtr != NULL) { 388 ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); 389 if (ewPtr->displayed) { 390 ewPtr->displayed = 0; 391 if (ewPtr->tkwin != NULL && tablePtr->tkwin != NULL) { 392 EmbWinUnmapNow(ewPtr->tkwin, tablePtr->tkwin); 393 } 394 } 395 } 396 } 397 } 398} 399 400/* 401 *-------------------------------------------------------------- 402 * 403 * EmbWinRequestProc -- 404 * This procedure is invoked by Tk_GeometryRequest for 405 * windows managed by the Table. 406 * 407 * Results: 408 * None. 409 * 410 * Side effects: 411 * Arranges for tkwin, and all its managed siblings, to 412 * be re-arranged at the next idle point. 413 * 414 *-------------------------------------------------------------- 415 */ 416static void 417EmbWinRequestProc(clientData, tkwin) 418 ClientData clientData; /* Table's information about 419 * window that got new preferred 420 * geometry. */ 421 Tk_Window tkwin; /* Other Tk-related information 422 * about the window. */ 423{ 424 register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData; 425 426 /* 427 * Resize depends on the sticky 428 */ 429 if (ewPtr->displayed && ewPtr->hPtr != NULL) { 430 Table *tablePtr = ewPtr->tablePtr; 431 int row, col, x, y, width, height; 432 433 TableParseArrayIndex(&row, &col, 434 Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr)); 435 if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, 436 col-tablePtr->colOffset, &x, &y, &width, &height, 437 0)) { 438 TableInvalidate(tablePtr, x, y, width, height, 0); 439 } 440 } 441} 442 443static void 444EmbWinRemove(TableEmbWindow *ewPtr) 445{ 446 Table *tablePtr = ewPtr->tablePtr; 447 448 if (ewPtr->tkwin != NULL) { 449 Tk_DeleteEventHandler(ewPtr->tkwin, StructureNotifyMask, 450 EmbWinStructureProc, (ClientData) ewPtr); 451 ewPtr->tkwin = NULL; 452 } 453 ewPtr->displayed = 0; 454 if (tablePtr->tkwin != NULL) { 455 int row, col, x, y, width, height; 456 457 TableParseArrayIndex(&row, &col, 458 Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr)); 459 /* this will cause windows removed from the table to actually 460 * cause the associated embdedded window hash data to be removed */ 461 Tcl_DeleteHashEntry(ewPtr->hPtr); 462 if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, 463 col-tablePtr->colOffset, &x, &y, &width, &height, 464 0)) 465 TableInvalidate(tablePtr, x, y, width, height, 1); 466 } 467 /* this will cause windows removed from the table to actually 468 * cause the associated embdedded window hash data to be removed */ 469 EmbWinCleanup(tablePtr, ewPtr); 470 ckfree((char *) ewPtr); 471} 472 473/* 474 *-------------------------------------------------------------- 475 * 476 * EmbWinLostSlaveProc -- 477 * This procedure is invoked by Tk whenever some other geometry 478 * claims control over a slave that used to be managed by us. 479 * 480 * Results: 481 * None. 482 * 483 * Side effects: 484 * Forgets all table-related information about the slave. 485 * 486 *-------------------------------------------------------------- 487 */ 488 489static void 490EmbWinLostSlaveProc(clientData, tkwin) 491 ClientData clientData; /* Table structure for slave window that 492 * was stolen away. */ 493 Tk_Window tkwin; /* Tk's handle for the slave window. */ 494{ 495 register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData; 496 497#if 0 498 Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr); 499#endif 500 EmbWinUnmapNow(tkwin, ewPtr->tablePtr->tkwin); 501 EmbWinRemove(ewPtr); 502} 503 504/* 505 *-------------------------------------------------------------- 506 * 507 * EmbWinStructureProc -- 508 * This procedure is invoked by the Tk event loop whenever 509 * StructureNotify events occur for a window that's embedded 510 * in a table widget. This procedure's only purpose is to 511 * clean up when windows are deleted. 512 * 513 * Results: 514 * None. 515 * 516 * Side effects: 517 * The window is disassociated from the window segment, and 518 * the portion of the table is redisplayed. 519 * 520 *-------------------------------------------------------------- 521 */ 522static void 523EmbWinStructureProc(clientData, eventPtr) 524 ClientData clientData; /* Pointer to record describing window item. */ 525 XEvent *eventPtr; /* Describes what just happened. */ 526{ 527 register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData; 528 529 if (eventPtr->type != DestroyNotify) { 530 return; 531 } 532 533 EmbWinRemove(ewPtr); 534} 535 536/* 537 *-------------------------------------------------------------- 538 * 539 * EmbWinDelete -- 540 * This procedure is invoked by ... whenever 541 * an embedded window is being deleted. 542 * 543 * Results: 544 * None. 545 * 546 * Side effects: 547 * The embedded window is deleted, if it exists, and any resources 548 * associated with it are released. 549 * 550 *-------------------------------------------------------------- 551 */ 552void 553EmbWinDelete(register Table *tablePtr, TableEmbWindow *ewPtr) 554{ 555 Tcl_HashEntry *entryPtr = ewPtr->hPtr; 556 557 if (ewPtr->tkwin != NULL) { 558 Tk_Window tkwin = ewPtr->tkwin; 559 /* 560 * Delete the event handler for the window before destroying 561 * the window, so that EmbWinStructureProc doesn't get called 562 * (we'll already do everything that it would have done, and 563 * it will just get confused). 564 */ 565 566 ewPtr->tkwin = NULL; 567 Tk_DeleteEventHandler(tkwin, StructureNotifyMask, 568 EmbWinStructureProc, (ClientData) ewPtr); 569 Tk_DestroyWindow(tkwin); 570 } 571 if (tablePtr->tkwin != NULL && entryPtr != NULL) { 572 int row, col, x, y, width, height; 573 TableParseArrayIndex(&row, &col, 574 Tcl_GetHashKey(tablePtr->winTable, entryPtr)); 575 Tcl_DeleteHashEntry(entryPtr); 576 577 if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, 578 col-tablePtr->colOffset, 579 &x, &y, &width, &height, 0)) 580 TableInvalidate(tablePtr, x, y, width, height, 0); 581 } 582#if 0 583 Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr); 584#endif 585 EmbWinCleanup(tablePtr, ewPtr); 586 ckfree((char *) ewPtr); 587} 588 589/* 590 *-------------------------------------------------------------- 591 * 592 * EmbWinConfigure -- 593 * This procedure is called to handle configuration options 594 * for an embedded window. 595 * 596 * Results: 597 * The return value is a standard Tcl result. If TCL_ERROR is 598 * returned, then the interp's result contains an error message.. 599 * 600 * Side effects: 601 * Configuration information for the embedded window changes, 602 * such as alignment, stretching, or name of the embedded 603 * window. 604 * 605 *-------------------------------------------------------------- 606 */ 607static int 608EmbWinConfigure(tablePtr, ewPtr, objc, objv) 609 Table *tablePtr; /* Information about table widget that 610 * contains embedded window. */ 611 TableEmbWindow *ewPtr; /* Embedded window to be configured. */ 612 int objc; /* Number of objs in objv. */ 613 Tcl_Obj *CONST objv[]; /* Obj type options. */ 614{ 615 Tcl_Interp *interp = tablePtr->interp; 616 Tk_Window oldWindow; 617 int i, result; 618 CONST84 char **argv; 619 620 oldWindow = ewPtr->tkwin; 621 622 /* Stringify */ 623 argv = (CONST84 char **) ckalloc((objc + 1) * sizeof(char *)); 624 for (i = 0; i < objc; i++) 625 argv[i] = Tcl_GetString(objv[i]); 626 argv[i] = NULL; 627 result = Tk_ConfigureWidget(interp, tablePtr->tkwin, 628 winConfigSpecs, objc, argv, (char *) ewPtr, 629 TK_CONFIG_ARGV_ONLY); 630 ckfree((char *) argv); 631 if (result != TCL_OK) { 632 return TCL_ERROR; 633 } 634 635 if (oldWindow != ewPtr->tkwin) { 636 ewPtr->displayed = 0; 637 if (oldWindow != NULL) { 638 Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, 639 EmbWinStructureProc, (ClientData) ewPtr); 640 Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL, 641 (ClientData) NULL); 642 EmbWinUnmapNow(oldWindow, tablePtr->tkwin); 643 } 644 if (ewPtr->tkwin != NULL) { 645 Tk_Window ancestor, parent; 646 647 /* 648 * Make sure that the table is either the parent of the 649 * embedded window or a descendant of that parent. Also, 650 * don't allow a top-level window to be managed inside 651 * a table. 652 */ 653 654 parent = Tk_Parent(ewPtr->tkwin); 655 for (ancestor = tablePtr->tkwin; ; 656 ancestor = Tk_Parent(ancestor)) { 657 if (ancestor == parent) { 658 break; 659 } 660 if (Tk_IsTopLevel(ancestor)) { 661 badMaster: 662 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), 663 "can't embed ", 664 Tk_PathName(ewPtr->tkwin), " in ", 665 Tk_PathName(tablePtr->tkwin), 666 (char *)NULL); 667 ewPtr->tkwin = NULL; 668 return TCL_ERROR; 669 } 670 } 671 if (Tk_IsTopLevel(ewPtr->tkwin) || 672 (ewPtr->tkwin == tablePtr->tkwin)) { 673 goto badMaster; 674 } 675 676 /* 677 * Take over geometry management for the window, plus create 678 * an event handler to find out when it is deleted. 679 */ 680 681 Tk_ManageGeometry(ewPtr->tkwin, &tableGeomType, (ClientData)ewPtr); 682 Tk_CreateEventHandler(ewPtr->tkwin, StructureNotifyMask, 683 EmbWinStructureProc, (ClientData) ewPtr); 684 } 685 } 686 return TCL_OK; 687} 688 689/* 690 *-------------------------------------------------------------- 691 * 692 * Table_WinMove -- 693 * This procedure is invoked by ... whenever 694 * an embedded window is being moved. 695 * 696 * Results: 697 * A standard Tcl result. 698 * 699 * Side effects: 700 * If an embedded window is in the dest cell, it is deleted. 701 * 702 *-------------------------------------------------------------- 703 */ 704int 705Table_WinMove(register Table *tablePtr, char *CONST srcPtr, 706 char *CONST destPtr, int flags) 707{ 708 int srow, scol, row, col, new; 709 Tcl_HashEntry *entryPtr; 710 TableEmbWindow *ewPtr; 711 712 if (TableGetIndex(tablePtr, srcPtr, &srow, &scol) != TCL_OK || 713 TableGetIndex(tablePtr, destPtr, &row, &col) != TCL_OK) { 714 return TCL_ERROR; 715 } 716 entryPtr = Tcl_FindHashEntry(tablePtr->winTable, srcPtr); 717 if (entryPtr == NULL) { 718 if (flags & INV_NO_ERR_MSG) { 719 return TCL_OK; 720 } else { 721 Tcl_AppendStringsToObj(Tcl_GetObjResult(tablePtr->interp), 722 "no window at index \"", srcPtr, "\"", (char *) NULL); 723 return TCL_ERROR; 724 } 725 } 726 /* avoid moving it to the same location */ 727 if (srow == row && scol == col) { 728 return TCL_OK; 729 } 730 /* get the window pointer */ 731 ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); 732 /* and free the old hash table entry */ 733 Tcl_DeleteHashEntry(entryPtr); 734 735 entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, destPtr, &new); 736 if (!new) { 737 /* window already there - just delete it */ 738 TableEmbWindow *ewPtrDel; 739 ewPtrDel = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); 740 /* This prevents the deletion of it's own entry, since we need it */ 741 ewPtrDel->hPtr = NULL; 742 EmbWinDelete(tablePtr, ewPtrDel); 743 } 744 /* set the new entry's value */ 745 Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); 746 ewPtr->hPtr = entryPtr; 747 748 if (flags & INV_FORCE) { 749 int x, y, w, h; 750 /* Invalidate old cell */ 751 if (TableCellVCoords(tablePtr, srow-tablePtr->rowOffset, 752 scol-tablePtr->colOffset, &x, &y, &w, &h, 0)) { 753 TableInvalidate(tablePtr, x, y, w, h, 0); 754 } 755 /* Invalidate new cell */ 756 if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, 757 col-tablePtr->colOffset, &x, &y, &w, &h, 0)) { 758 TableInvalidate(tablePtr, x, y, w, h, 0); 759 } 760 } 761 return TCL_OK; 762} 763 764/* 765 *-------------------------------------------------------------- 766 * 767 * Table_WinDelete -- 768 * This procedure is invoked by ... whenever 769 * an embedded window is being delete. 770 * 771 * Results: 772 * A standard Tcl result. 773 * 774 * Side effects: 775 * Window info will be deleted. 776 * 777 *-------------------------------------------------------------- 778 */ 779int 780Table_WinDelete(register Table *tablePtr, char *CONST idxPtr) 781{ 782 Tcl_HashEntry *entryPtr; 783 784 entryPtr = Tcl_FindHashEntry(tablePtr->winTable, idxPtr); 785 if (entryPtr != NULL) { 786 /* get the window pointer & clean up data associated with it */ 787 EmbWinDelete(tablePtr, (TableEmbWindow *) Tcl_GetHashValue(entryPtr)); 788 } 789 return TCL_OK; 790} 791 792/* 793 *-------------------------------------------------------------- 794 * 795 * Table_WindowCmd -- 796 * This procedure is invoked to process the window method 797 * that corresponds to a widget managed by this module. 798 * See the user documentation for details on what it does. 799 * 800 * Results: 801 * A standard Tcl result. 802 * 803 * Side effects: 804 * See the user documentation. 805 * 806 *-------------------------------------------------------------- 807 */ 808int 809Table_WindowCmd(ClientData clientData, register Tcl_Interp *interp, 810 int objc, Tcl_Obj *CONST objv[]) 811{ 812 register Table *tablePtr = (Table *)clientData; 813 int result = TCL_OK, cmdIndex, row, col, x, y, width, height, i, new; 814 TableEmbWindow *ewPtr; 815 Tcl_HashEntry *entryPtr; 816 Tcl_HashSearch search; 817 char buf[INDEX_BUFSIZE], *keybuf, *winname; 818 819 if (objc < 3) { 820 Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?"); 821 return TCL_ERROR; 822 } 823 824 /* parse the next argument */ 825 if (Tcl_GetIndexFromObj(interp, objv[2], winCmdNames, 826 "option", 0, &cmdIndex) != TCL_OK) { 827 return TCL_ERROR; 828 } 829 switch ((enum winCommand) cmdIndex) { 830 case WIN_CGET: 831 if (objc != 5) { 832 Tcl_WrongNumArgs(interp, 3, objv, "index option"); 833 return TCL_ERROR; 834 } 835 entryPtr = Tcl_FindHashEntry(tablePtr->winTable, 836 Tcl_GetString(objv[3])); 837 if (entryPtr == NULL) { 838 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), 839 "no window at index \"", 840 Tcl_GetString(objv[3]), "\"", (char *)NULL); 841 return TCL_ERROR; 842 } else { 843 ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); 844 result = Tk_ConfigureValue(interp, tablePtr->tkwin, winConfigSpecs, 845 (char *) ewPtr, 846 Tcl_GetString(objv[4]), 0); 847 } 848 return result; /* CGET */ 849 850 case WIN_CONFIGURE: 851 if (objc < 4) { 852 Tcl_WrongNumArgs(interp, 3, objv, "index ?arg arg ...?"); 853 return TCL_ERROR; 854 } 855 if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR) { 856 return TCL_ERROR; 857 } 858 TableMakeArrayIndex(row, col, buf); 859 entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, &new); 860 861 if (new) { 862 /* create the structure */ 863 ewPtr = TableNewEmbWindow(tablePtr); 864 865 /* insert it into the table */ 866 Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); 867 ewPtr->hPtr = entryPtr; 868 869 /* configure the window structure */ 870 result = EmbWinConfigure(tablePtr, ewPtr, objc-4, objv+4); 871 if (result == TCL_ERROR) { 872 /* release the structure */ 873 EmbWinCleanup(tablePtr, ewPtr); 874 ckfree((char *) ewPtr); 875 876 /* and free the hash table entry */ 877 Tcl_DeleteHashEntry(entryPtr); 878 } 879 } else { 880 /* window exists, do a reconfig if we have enough args */ 881 /* get the window pointer from the table */ 882 ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); 883 884 /* 5 args means that there are values to replace */ 885 if (objc > 5) { 886 /* and do a reconfigure */ 887 result = EmbWinConfigure(tablePtr, ewPtr, objc-4, objv+4); 888 } 889 } 890 if (result == TCL_ERROR) { 891 return TCL_ERROR; 892 } 893 894 /* 895 * If there were less than 6 args, we need 896 * to do a printout of the config, even for new windows 897 */ 898 if (objc < 6) { 899 result = Tk_ConfigureInfo(interp, tablePtr->tkwin, winConfigSpecs, 900 (char *) ewPtr, (objc == 5)? 901 Tcl_GetString(objv[4]) : NULL, 0); 902 } else { 903 /* Otherwise we reconfigured so invalidate 904 * the table for a redraw */ 905 if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, 906 col-tablePtr->colOffset, 907 &x, &y, &width, &height, 0)) { 908 TableInvalidate(tablePtr, x, y, width, height, 1); 909 } 910 } 911 return result; /* CONFIGURE */ 912 913 case WIN_DELETE: 914 if (objc < 4) { 915 Tcl_WrongNumArgs(interp, 3, objv, "index ?index ...?"); 916 return TCL_ERROR; 917 } 918 for (i = 3; i < objc; i++) { 919 Table_WinDelete(tablePtr, Tcl_GetString(objv[i])); 920 } 921 break; 922 923 case WIN_MOVE: 924 if (objc != 5) { 925 Tcl_WrongNumArgs(interp, 3, objv, "srcIndex destIndex"); 926 return TCL_ERROR; 927 } 928 result = Table_WinMove(tablePtr, Tcl_GetString(objv[3]), 929 Tcl_GetString(objv[4]), INV_FORCE); 930 break; 931 932 case WIN_NAMES: { 933 Tcl_Obj *objPtr = Tcl_NewObj(); 934 935 /* just print out the window names */ 936 if (objc < 3 || objc > 4) { 937 Tcl_WrongNumArgs(interp, 3, objv, "?pattern?"); 938 return TCL_ERROR; 939 } 940 winname = (objc == 4) ? Tcl_GetString(objv[3]) : NULL; 941 entryPtr = Tcl_FirstHashEntry(tablePtr->winTable, &search); 942 while (entryPtr != NULL) { 943 keybuf = Tcl_GetHashKey(tablePtr->winTable, entryPtr); 944 if (objc == 3 || Tcl_StringMatch(keybuf, winname)) { 945 Tcl_ListObjAppendElement(NULL, objPtr, 946 Tcl_NewStringObj(keybuf, -1)); 947 } 948 entryPtr = Tcl_NextHashEntry(&search); 949 } 950 Tcl_SetObjResult(interp, TableCellSortObj(interp, objPtr)); 951 break; 952 } 953 } 954 return TCL_OK; 955} 956