1/* 2 * tkCmds.c -- 3 * 4 * This file contains a collection of Tk-related Tcl commands that didn't 5 * fit in any particular file of the toolkit. 6 * 7 * Copyright (c) 1990-1994 The Regents of the University of California. 8 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 9 * Copyright (c) 2000 Scriptics Corporation. 10 * 11 * See the file "license.terms" for information on usage and redistribution of 12 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * RCS: @(#) $Id$ 15 */ 16 17#include "tkInt.h" 18 19#if defined(WIN32) 20#include "tkWinInt.h" 21#elif defined(MAC_OSX_TK) 22#include "tkMacOSXInt.h" 23#else 24#include "tkUnixInt.h" 25#endif 26 27/* 28 * Forward declarations for functions defined later in this file: 29 */ 30 31static TkWindow * GetTopHierarchy(Tk_Window tkwin); 32static char * WaitVariableProc(ClientData clientData, 33 Tcl_Interp *interp, const char *name1, 34 const char *name2, int flags); 35static void WaitVisibilityProc(ClientData clientData, 36 XEvent *eventPtr); 37static void WaitWindowProc(ClientData clientData, 38 XEvent *eventPtr); 39 40/* 41 *---------------------------------------------------------------------- 42 * 43 * Tk_BellObjCmd -- 44 * 45 * This function is invoked to process the "bell" Tcl command. See the 46 * user documentation for details on what it does. 47 * 48 * Results: 49 * A standard Tcl result. 50 * 51 * Side effects: 52 * See the user documentation. 53 * 54 *---------------------------------------------------------------------- 55 */ 56 57int 58Tk_BellObjCmd( 59 ClientData clientData, /* Main window associated with interpreter. */ 60 Tcl_Interp *interp, /* Current interpreter. */ 61 int objc, /* Number of arguments. */ 62 Tcl_Obj *const objv[]) /* Argument objects. */ 63{ 64 static const char *bellOptions[] = { 65 "-displayof", "-nice", NULL 66 }; 67 enum options { TK_BELL_DISPLAYOF, TK_BELL_NICE }; 68 Tk_Window tkwin = (Tk_Window) clientData; 69 int i, index, nice = 0; 70 71 if (objc > 4) { 72 wrongArgs: 73 Tcl_WrongNumArgs(interp, 1, objv, "?-displayof window? ?-nice?"); 74 return TCL_ERROR; 75 } 76 77 for (i = 1; i < objc; i++) { 78 if (Tcl_GetIndexFromObj(interp, objv[i], bellOptions, "option", 0, 79 &index) != TCL_OK) { 80 return TCL_ERROR; 81 } 82 switch ((enum options) index) { 83 case TK_BELL_DISPLAYOF: 84 if (++i >= objc) { 85 goto wrongArgs; 86 } 87 tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[i]), tkwin); 88 if (tkwin == NULL) { 89 return TCL_ERROR; 90 } 91 break; 92 case TK_BELL_NICE: 93 nice = 1; 94 break; 95 } 96 } 97 XBell(Tk_Display(tkwin), 0); 98 if (!nice) { 99 XForceScreenSaver(Tk_Display(tkwin), ScreenSaverReset); 100 } 101 XFlush(Tk_Display(tkwin)); 102 return TCL_OK; 103} 104 105/* 106 *---------------------------------------------------------------------- 107 * 108 * Tk_BindObjCmd -- 109 * 110 * This function is invoked to process the "bind" Tcl command. See the 111 * user documentation for details on what it does. 112 * 113 * Results: 114 * A standard Tcl result. 115 * 116 * Side effects: 117 * See the user documentation. 118 * 119 *---------------------------------------------------------------------- 120 */ 121 122int 123Tk_BindObjCmd( 124 ClientData clientData, /* Main window associated with interpreter. */ 125 Tcl_Interp *interp, /* Current interpreter. */ 126 int objc, /* Number of arguments. */ 127 Tcl_Obj *const objv[]) /* Argument objects. */ 128{ 129 Tk_Window tkwin = (Tk_Window) clientData; 130 TkWindow *winPtr; 131 ClientData object; 132 char *string; 133 134 if ((objc < 2) || (objc > 4)) { 135 Tcl_WrongNumArgs(interp, 1, objv, "window ?pattern? ?command?"); 136 return TCL_ERROR; 137 } 138 string = Tcl_GetString(objv[1]); 139 140 /* 141 * Bind tags either a window name or a tag name for the first argument. 142 * If the argument starts with ".", assume it is a window; otherwise, it 143 * is a tag. 144 */ 145 146 if (string[0] == '.') { 147 winPtr = (TkWindow *) Tk_NameToWindow(interp, string, tkwin); 148 if (winPtr == NULL) { 149 return TCL_ERROR; 150 } 151 object = (ClientData) winPtr->pathName; 152 } else { 153 winPtr = (TkWindow *) clientData; 154 object = (ClientData) Tk_GetUid(string); 155 } 156 157 /* 158 * If there are four arguments, the command is modifying a binding. If 159 * there are three arguments, the command is querying a binding. If there 160 * are only two arguments, the command is querying all the bindings for 161 * the given tag/window. 162 */ 163 164 if (objc == 4) { 165 int append = 0; 166 unsigned long mask; 167 char *sequence, *script; 168 sequence = Tcl_GetString(objv[2]); 169 script = Tcl_GetString(objv[3]); 170 171 /* 172 * If the script is null, just delete the binding. 173 */ 174 175 if (script[0] == 0) { 176 return Tk_DeleteBinding(interp, winPtr->mainPtr->bindingTable, 177 object, sequence); 178 } 179 180 /* 181 * If the script begins with "+", append this script to the existing 182 * binding. 183 */ 184 185 if (script[0] == '+') { 186 script++; 187 append = 1; 188 } 189 mask = Tk_CreateBinding(interp, winPtr->mainPtr->bindingTable, 190 object, sequence, script, append); 191 if (mask == 0) { 192 return TCL_ERROR; 193 } 194 } else if (objc == 3) { 195 const char *command; 196 197 command = Tk_GetBinding(interp, winPtr->mainPtr->bindingTable, 198 object, Tcl_GetString(objv[2])); 199 if (command == NULL) { 200 Tcl_ResetResult(interp); 201 return TCL_OK; 202 } 203 Tcl_SetResult(interp, (char *) command, TCL_STATIC); 204 } else { 205 Tk_GetAllBindings(interp, winPtr->mainPtr->bindingTable, object); 206 } 207 return TCL_OK; 208} 209 210/* 211 *---------------------------------------------------------------------- 212 * 213 * TkBindEventProc -- 214 * 215 * This function is invoked by Tk_HandleEvent for each event; it causes 216 * any appropriate bindings for that event to be invoked. 217 * 218 * Results: 219 * None. 220 * 221 * Side effects: 222 * Depends on what bindings have been established with the "bind" 223 * command. 224 * 225 *---------------------------------------------------------------------- 226 */ 227 228void 229TkBindEventProc( 230 TkWindow *winPtr, /* Pointer to info about window. */ 231 XEvent *eventPtr) /* Information about event. */ 232{ 233#define MAX_OBJS 20 234 ClientData objects[MAX_OBJS], *objPtr; 235 TkWindow *topLevPtr; 236 int i, count; 237 char *p; 238 Tcl_HashEntry *hPtr; 239 240 if ((winPtr->mainPtr == NULL) || (winPtr->mainPtr->bindingTable == NULL)) { 241 return; 242 } 243 244 objPtr = objects; 245 if (winPtr->numTags != 0) { 246 /* 247 * Make a copy of the tags for the window, replacing window names with 248 * pointers to the pathName from the appropriate window. 249 */ 250 251 if (winPtr->numTags > MAX_OBJS) { 252 objPtr = (ClientData *) ckalloc((unsigned) 253 (winPtr->numTags * sizeof(ClientData))); 254 } 255 for (i = 0; i < winPtr->numTags; i++) { 256 p = (char *) winPtr->tagPtr[i]; 257 if (*p == '.') { 258 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, p); 259 if (hPtr != NULL) { 260 p = ((TkWindow *) Tcl_GetHashValue(hPtr))->pathName; 261 } else { 262 p = NULL; 263 } 264 } 265 objPtr[i] = (ClientData) p; 266 } 267 count = winPtr->numTags; 268 } else { 269 objPtr[0] = (ClientData) winPtr->pathName; 270 objPtr[1] = (ClientData) winPtr->classUid; 271 for (topLevPtr = winPtr; 272 (topLevPtr != NULL) && !(topLevPtr->flags & TK_TOP_HIERARCHY); 273 topLevPtr = topLevPtr->parentPtr) { 274 /* Empty loop body. */ 275 } 276 if ((winPtr != topLevPtr) && (topLevPtr != NULL)) { 277 count = 4; 278 objPtr[2] = (ClientData) topLevPtr->pathName; 279 } else { 280 count = 3; 281 } 282 objPtr[count-1] = (ClientData) Tk_GetUid("all"); 283 } 284 Tk_BindEvent(winPtr->mainPtr->bindingTable, eventPtr, (Tk_Window) winPtr, 285 count, objPtr); 286 if (objPtr != objects) { 287 ckfree((char *) objPtr); 288 } 289} 290 291/* 292 *---------------------------------------------------------------------- 293 * 294 * Tk_BindtagsObjCmd -- 295 * 296 * This function is invoked to process the "bindtags" Tcl command. See 297 * the user documentation for details on what it does. 298 * 299 * Results: 300 * A standard Tcl result. 301 * 302 * Side effects: 303 * See the user documentation. 304 * 305 *---------------------------------------------------------------------- 306 */ 307 308int 309Tk_BindtagsObjCmd( 310 ClientData clientData, /* Main window associated with interpreter. */ 311 Tcl_Interp *interp, /* Current interpreter. */ 312 int objc, /* Number of arguments. */ 313 Tcl_Obj *const objv[]) /* Argument objects. */ 314{ 315 Tk_Window tkwin = (Tk_Window) clientData; 316 TkWindow *winPtr, *winPtr2; 317 int i, length; 318 char *p; 319 Tcl_Obj *listPtr, **tags; 320 321 if ((objc < 2) || (objc > 3)) { 322 Tcl_WrongNumArgs(interp, 1, objv, "window ?taglist?"); 323 return TCL_ERROR; 324 } 325 winPtr = (TkWindow *) Tk_NameToWindow(interp, Tcl_GetString(objv[1]), 326 tkwin); 327 if (winPtr == NULL) { 328 return TCL_ERROR; 329 } 330 if (objc == 2) { 331 listPtr = Tcl_NewObj(); 332 Tcl_IncrRefCount(listPtr); 333 if (winPtr->numTags == 0) { 334 Tcl_ListObjAppendElement(interp, listPtr, 335 Tcl_NewStringObj(winPtr->pathName, -1)); 336 Tcl_ListObjAppendElement(interp, listPtr, 337 Tcl_NewStringObj(winPtr->classUid, -1)); 338 winPtr2 = winPtr; 339 while ((winPtr2 != NULL) && !(Tk_TopWinHierarchy(winPtr2))) { 340 winPtr2 = winPtr2->parentPtr; 341 } 342 if ((winPtr != winPtr2) && (winPtr2 != NULL)) { 343 Tcl_ListObjAppendElement(interp, listPtr, 344 Tcl_NewStringObj(winPtr2->pathName, -1)); 345 } 346 Tcl_ListObjAppendElement(interp, listPtr, 347 Tcl_NewStringObj("all", -1)); 348 } else { 349 for (i = 0; i < winPtr->numTags; i++) { 350 Tcl_ListObjAppendElement(interp, listPtr, 351 Tcl_NewStringObj((char *)winPtr->tagPtr[i], -1)); 352 } 353 } 354 Tcl_SetObjResult(interp, listPtr); 355 Tcl_DecrRefCount(listPtr); 356 return TCL_OK; 357 } 358 if (winPtr->tagPtr != NULL) { 359 TkFreeBindingTags(winPtr); 360 } 361 if (Tcl_ListObjGetElements(interp, objv[2], &length, &tags) != TCL_OK) { 362 return TCL_ERROR; 363 } 364 if (length == 0) { 365 return TCL_OK; 366 } 367 368 winPtr->numTags = length; 369 winPtr->tagPtr = (ClientData *) ckalloc((unsigned) 370 (length * sizeof(ClientData))); 371 for (i = 0; i < length; i++) { 372 p = Tcl_GetString(tags[i]); 373 if (p[0] == '.') { 374 char *copy; 375 376 /* 377 * Handle names starting with "." specially: store a malloc'ed 378 * string, rather than a Uid; at event time we'll look up the name 379 * in the window table and use the corresponding window, if there 380 * is one. 381 */ 382 383 copy = (char *) ckalloc((unsigned) (strlen(p) + 1)); 384 strcpy(copy, p); 385 winPtr->tagPtr[i] = (ClientData) copy; 386 } else { 387 winPtr->tagPtr[i] = (ClientData) Tk_GetUid(p); 388 } 389 } 390 return TCL_OK; 391} 392 393/* 394 *---------------------------------------------------------------------- 395 * 396 * TkFreeBindingTags -- 397 * 398 * This function is called to free all of the binding tags associated 399 * with a window; typically it is only invoked where there are 400 * window-specific tags. 401 * 402 * Results: 403 * None. 404 * 405 * Side effects: 406 * Any binding tags for winPtr are freed. 407 * 408 *---------------------------------------------------------------------- 409 */ 410 411void 412TkFreeBindingTags( 413 TkWindow *winPtr) /* Window whose tags are to be released. */ 414{ 415 int i; 416 char *p; 417 418 for (i = 0; i < winPtr->numTags; i++) { 419 p = (char *) (winPtr->tagPtr[i]); 420 if (*p == '.') { 421 /* 422 * Names starting with "." are malloced rather than Uids, so they 423 * have to be freed. 424 */ 425 426 ckfree(p); 427 } 428 } 429 ckfree((char *) winPtr->tagPtr); 430 winPtr->numTags = 0; 431 winPtr->tagPtr = NULL; 432} 433 434/* 435 *---------------------------------------------------------------------- 436 * 437 * Tk_DestroyObjCmd -- 438 * 439 * This function is invoked to process the "destroy" Tcl command. See the 440 * user documentation for details on what it does. 441 * 442 * Results: 443 * A standard Tcl result. 444 * 445 * Side effects: 446 * See the user documentation. 447 * 448 *---------------------------------------------------------------------- 449 */ 450 451int 452Tk_DestroyObjCmd( 453 ClientData clientData, /* Main window associated with interpreter. */ 454 Tcl_Interp *interp, /* Current interpreter. */ 455 int objc, /* Number of arguments. */ 456 Tcl_Obj *const objv[]) /* Argument objects. */ 457{ 458 Tk_Window window; 459 Tk_Window tkwin = (Tk_Window) clientData; 460 int i; 461 462 for (i = 1; i < objc; i++) { 463 window = Tk_NameToWindow(interp, Tcl_GetString(objv[i]), tkwin); 464 if (window == NULL) { 465 Tcl_ResetResult(interp); 466 continue; 467 } 468 Tk_DestroyWindow(window); 469 if (window == tkwin) { 470 /* 471 * We just deleted the main window for the application! This makes 472 * it impossible to do anything more (tkwin isn't valid anymore). 473 */ 474 475 break; 476 } 477 } 478 return TCL_OK; 479} 480 481/* 482 *---------------------------------------------------------------------- 483 * 484 * Tk_LowerObjCmd -- 485 * 486 * This function is invoked to process the "lower" Tcl command. See the 487 * user documentation for details on what it does. 488 * 489 * Results: 490 * A standard Tcl result. 491 * 492 * Side effects: 493 * See the user documentation. 494 * 495 *---------------------------------------------------------------------- 496 */ 497 498 /* ARGSUSED */ 499int 500Tk_LowerObjCmd( 501 ClientData clientData, /* Main window associated with interpreter. */ 502 Tcl_Interp *interp, /* Current interpreter. */ 503 int objc, /* Number of arguments. */ 504 Tcl_Obj *const objv[]) /* Argument objects. */ 505{ 506 Tk_Window mainwin = (Tk_Window) clientData; 507 Tk_Window tkwin, other; 508 509 if ((objc != 2) && (objc != 3)) { 510 Tcl_WrongNumArgs(interp, 1, objv, "window ?belowThis?"); 511 return TCL_ERROR; 512 } 513 514 tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), mainwin); 515 if (tkwin == NULL) { 516 return TCL_ERROR; 517 } 518 if (objc == 2) { 519 other = NULL; 520 } else { 521 other = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainwin); 522 if (other == NULL) { 523 return TCL_ERROR; 524 } 525 } 526 if (Tk_RestackWindow(tkwin, Below, other) != TCL_OK) { 527 Tcl_AppendResult(interp, "can't lower \"", Tcl_GetString(objv[1]), 528 "\" below \"", (other ? Tcl_GetString(objv[2]) : ""), 529 "\"", NULL); 530 return TCL_ERROR; 531 } 532 return TCL_OK; 533} 534 535/* 536 *---------------------------------------------------------------------- 537 * 538 * Tk_RaiseObjCmd -- 539 * 540 * This function is invoked to process the "raise" Tcl command. See the 541 * user documentation for details on what it does. 542 * 543 * Results: 544 * A standard Tcl result. 545 * 546 * Side effects: 547 * See the user documentation. 548 * 549 *---------------------------------------------------------------------- 550 */ 551 552 /* ARGSUSED */ 553int 554Tk_RaiseObjCmd( 555 ClientData clientData, /* Main window associated with interpreter. */ 556 Tcl_Interp *interp, /* Current interpreter. */ 557 int objc, /* Number of arguments. */ 558 Tcl_Obj *const objv[]) /* Argument objects. */ 559{ 560 Tk_Window mainwin = (Tk_Window) clientData; 561 Tk_Window tkwin, other; 562 563 if ((objc != 2) && (objc != 3)) { 564 Tcl_WrongNumArgs(interp, 1, objv, "window ?aboveThis?"); 565 return TCL_ERROR; 566 } 567 568 tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), mainwin); 569 if (tkwin == NULL) { 570 return TCL_ERROR; 571 } 572 if (objc == 2) { 573 other = NULL; 574 } else { 575 other = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainwin); 576 if (other == NULL) { 577 return TCL_ERROR; 578 } 579 } 580 if (Tk_RestackWindow(tkwin, Above, other) != TCL_OK) { 581 Tcl_AppendResult(interp, "can't raise \"", Tcl_GetString(objv[1]), 582 "\" above \"", (other ? Tcl_GetString(objv[2]) : ""), 583 "\"", NULL); 584 return TCL_ERROR; 585 } 586 return TCL_OK; 587} 588 589/* 590 *---------------------------------------------------------------------- 591 * 592 * Tk_TkObjCmd -- 593 * 594 * This function is invoked to process the "tk" Tcl command. See the user 595 * documentation for details on what it does. 596 * 597 * Results: 598 * A standard Tcl result. 599 * 600 * Side effects: 601 * See the user documentation. 602 * 603 *---------------------------------------------------------------------- 604 */ 605 606int 607Tk_TkObjCmd( 608 ClientData clientData, /* Main window associated with interpreter. */ 609 Tcl_Interp *interp, /* Current interpreter. */ 610 int objc, /* Number of arguments. */ 611 Tcl_Obj *const objv[]) /* Argument objects. */ 612{ 613 int index; 614 Tk_Window tkwin; 615 static const char *optionStrings[] = { 616 "appname", "caret", "scaling", "useinputmethods", 617 "windowingsystem", "inactive", NULL 618 }; 619 enum options { 620 TK_APPNAME, TK_CARET, TK_SCALING, TK_USE_IM, 621 TK_WINDOWINGSYSTEM, TK_INACTIVE 622 }; 623 624 tkwin = (Tk_Window) clientData; 625 626 if (objc < 2) { 627 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); 628 return TCL_ERROR; 629 } 630 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 631 &index) != TCL_OK) { 632 return TCL_ERROR; 633 } 634 635 switch ((enum options) index) { 636 case TK_APPNAME: { 637 TkWindow *winPtr; 638 char *string; 639 640 if (Tcl_IsSafe(interp)) { 641 Tcl_SetResult(interp, 642 "appname not accessible in a safe interpreter", 643 TCL_STATIC); 644 return TCL_ERROR; 645 } 646 647 winPtr = (TkWindow *) tkwin; 648 649 if (objc > 3) { 650 Tcl_WrongNumArgs(interp, 2, objv, "?newName?"); 651 return TCL_ERROR; 652 } 653 if (objc == 3) { 654 string = Tcl_GetString(objv[2]); 655 winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, string)); 656 } 657 Tcl_AppendResult(interp, winPtr->nameUid, NULL); 658 break; 659 } 660 case TK_CARET: { 661 Tcl_Obj *objPtr; 662 TkCaret *caretPtr; 663 Tk_Window window; 664 static const char *caretStrings[] = { 665 "-x", "-y", "-height", NULL 666 }; 667 enum caretOptions { 668 TK_CARET_X, TK_CARET_Y, TK_CARET_HEIGHT 669 }; 670 671 if ((objc < 3) || ((objc > 4) && !(objc & 1))) { 672 Tcl_WrongNumArgs(interp, 2, objv, 673 "window ?-x x? ?-y y? ?-height height?"); 674 return TCL_ERROR; 675 } 676 window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin); 677 if (window == NULL) { 678 return TCL_ERROR; 679 } 680 caretPtr = &(((TkWindow *) window)->dispPtr->caret); 681 if (objc == 3) { 682 /* 683 * Return all the current values 684 */ 685 686 objPtr = Tcl_NewObj(); 687 Tcl_ListObjAppendElement(interp, objPtr, 688 Tcl_NewStringObj("-height", 7)); 689 Tcl_ListObjAppendElement(interp, objPtr, 690 Tcl_NewIntObj(caretPtr->height)); 691 Tcl_ListObjAppendElement(interp, objPtr, 692 Tcl_NewStringObj("-x", 2)); 693 Tcl_ListObjAppendElement(interp, objPtr, 694 Tcl_NewIntObj(caretPtr->x)); 695 Tcl_ListObjAppendElement(interp, objPtr, 696 Tcl_NewStringObj("-y", 2)); 697 Tcl_ListObjAppendElement(interp, objPtr, 698 Tcl_NewIntObj(caretPtr->y)); 699 Tcl_SetObjResult(interp, objPtr); 700 } else if (objc == 4) { 701 int value; 702 703 /* 704 * Return the current value of the selected option 705 */ 706 707 if (Tcl_GetIndexFromObj(interp, objv[3], caretStrings, 708 "caret option", 0, &index) != TCL_OK) { 709 return TCL_ERROR; 710 } 711 if (index == TK_CARET_X) { 712 value = caretPtr->x; 713 } else if (index == TK_CARET_Y) { 714 value = caretPtr->y; 715 } else /* if (index == TK_CARET_HEIGHT) -- last case */ { 716 value = caretPtr->height; 717 } 718 Tcl_SetIntObj(Tcl_GetObjResult(interp), value); 719 } else { 720 int i, value, x = 0, y = 0, height = -1; 721 722 for (i = 3; i < objc; i += 2) { 723 if ((Tcl_GetIndexFromObj(interp, objv[i], caretStrings, 724 "caret option", 0, &index) != TCL_OK) || 725 Tcl_GetIntFromObj(interp,objv[i+1],&value) != TCL_OK) { 726 return TCL_ERROR; 727 } 728 if (index == TK_CARET_X) { 729 x = value; 730 } else if (index == TK_CARET_Y) { 731 y = value; 732 } else /* if (index == TK_CARET_HEIGHT) -- last case */ { 733 height = value; 734 } 735 } 736 if (height < 0) { 737 height = Tk_Height(window); 738 } 739 Tk_SetCaretPos(window, x, y, height); 740 } 741 break; 742 } 743 case TK_SCALING: { 744 Screen *screenPtr; 745 int skip, width, height; 746 double d; 747 748 if (Tcl_IsSafe(interp)) { 749 Tcl_SetResult(interp, 750 "scaling not accessible in a safe interpreter", 751 TCL_STATIC); 752 return TCL_ERROR; 753 } 754 755 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 756 if (skip < 0) { 757 return TCL_ERROR; 758 } 759 screenPtr = Tk_Screen(tkwin); 760 if (objc - skip == 2) { 761 d = 25.4 / 72; 762 d *= WidthOfScreen(screenPtr); 763 d /= WidthMMOfScreen(screenPtr); 764 Tcl_SetDoubleObj(Tcl_GetObjResult(interp), d); 765 } else if (objc - skip == 3) { 766 if (Tcl_GetDoubleFromObj(interp, objv[2+skip], &d) != TCL_OK) { 767 return TCL_ERROR; 768 } 769 d = (25.4 / 72) / d; 770 width = (int) (d * WidthOfScreen(screenPtr) + 0.5); 771 if (width <= 0) { 772 width = 1; 773 } 774 height = (int) (d * HeightOfScreen(screenPtr) + 0.5); 775 if (height <= 0) { 776 height = 1; 777 } 778 WidthMMOfScreen(screenPtr) = width; 779 HeightMMOfScreen(screenPtr) = height; 780 } else { 781 Tcl_WrongNumArgs(interp, 2, objv, 782 "?-displayof window? ?factor?"); 783 return TCL_ERROR; 784 } 785 break; 786 } 787 case TK_USE_IM: { 788 TkDisplay *dispPtr; 789 int skip; 790 791 if (Tcl_IsSafe(interp)) { 792 Tcl_SetResult(interp, 793 "useinputmethods not accessible in a safe interpreter", 794 TCL_STATIC); 795 return TCL_ERROR; 796 } 797 798 skip = TkGetDisplayOf(interp, objc-2, objv+2, &tkwin); 799 if (skip < 0) { 800 return TCL_ERROR; 801 } 802 dispPtr = ((TkWindow *) tkwin)->dispPtr; 803 if ((objc - skip) == 3) { 804 /* 805 * In the case where TK_USE_INPUT_METHODS is not defined, this 806 * will be ignored and we will always return 0. That will indicate 807 * to the user that input methods are just not available. 808 */ 809 810 int boolVal; 811 812 if (Tcl_GetBooleanFromObj(interp, objv[2+skip], 813 &boolVal) != TCL_OK) { 814 return TCL_ERROR; 815 } 816#ifdef TK_USE_INPUT_METHODS 817 if (boolVal) { 818 dispPtr->flags |= TK_DISPLAY_USE_IM; 819 } else { 820 dispPtr->flags &= ~TK_DISPLAY_USE_IM; 821 } 822#endif /* TK_USE_INPUT_METHODS */ 823 } else if ((objc - skip) != 2) { 824 Tcl_WrongNumArgs(interp, 2, objv, 825 "?-displayof window? ?boolean?"); 826 return TCL_ERROR; 827 } 828 Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 829 (int) (dispPtr->flags & TK_DISPLAY_USE_IM)); 830 break; 831 } 832 case TK_WINDOWINGSYSTEM: { 833 const char *windowingsystem; 834 835 if (objc != 2) { 836 Tcl_WrongNumArgs(interp, 2, objv, NULL); 837 return TCL_ERROR; 838 } 839#if defined(WIN32) 840 windowingsystem = "win32"; 841#elif defined(MAC_OSX_TK) 842 windowingsystem = "aqua"; 843#else 844 windowingsystem = "x11"; 845#endif 846 Tcl_SetStringObj(Tcl_GetObjResult(interp), windowingsystem, -1); 847 break; 848 } 849 case TK_INACTIVE: { 850 int skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 851 852 if (skip < 0) { 853 return TCL_ERROR; 854 } 855 if (objc - skip == 2) { 856 long inactive; 857 858 inactive = (Tcl_IsSafe(interp) ? -1 : 859 Tk_GetUserInactiveTime(Tk_Display(tkwin))); 860 Tcl_SetObjResult(interp, Tcl_NewLongObj(inactive)); 861 862 } else if (objc - skip == 3) { 863 char *string; 864 865 string = Tcl_GetString(objv[objc-1]); 866 if (strcmp(string, "reset") != 0) { 867 Tcl_Obj *msg = Tcl_NewStringObj("bad option \"", -1); 868 869 Tcl_AppendStringsToObj(msg, string, "\": must be reset", NULL); 870 Tcl_SetObjResult(interp, msg); 871 return TCL_ERROR; 872 } 873 if (Tcl_IsSafe(interp)) { 874 Tcl_SetResult(interp, 875 "resetting the user inactivity timer " 876 "is not allowed in a safe interpreter", TCL_STATIC); 877 return TCL_ERROR; 878 } 879 Tk_ResetUserInactiveTime(Tk_Display(tkwin)); 880 Tcl_ResetResult(interp); 881 } else { 882 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? ?reset?"); 883 return TCL_ERROR; 884 } 885 break; 886 } 887 } 888 return TCL_OK; 889} 890 891/* 892 *---------------------------------------------------------------------- 893 * 894 * Tk_TkwaitObjCmd -- 895 * 896 * This function is invoked to process the "tkwait" Tcl command. See the 897 * user documentation for details on what it does. 898 * 899 * Results: 900 * A standard Tcl result. 901 * 902 * Side effects: 903 * See the user documentation. 904 * 905 *---------------------------------------------------------------------- 906 */ 907 908 /* ARGSUSED */ 909int 910Tk_TkwaitObjCmd( 911 ClientData clientData, /* Main window associated with interpreter. */ 912 Tcl_Interp *interp, /* Current interpreter. */ 913 int objc, /* Number of arguments. */ 914 Tcl_Obj *const objv[]) /* Argument objects. */ 915{ 916 Tk_Window tkwin = (Tk_Window) clientData; 917 int done, index; 918 static const char *optionStrings[] = { 919 "variable", "visibility", "window", NULL 920 }; 921 enum options { 922 TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW 923 }; 924 925 if (objc != 3) { 926 Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name"); 927 return TCL_ERROR; 928 } 929 930 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 931 &index) != TCL_OK) { 932 return TCL_ERROR; 933 } 934 935 switch ((enum options) index) { 936 case TKWAIT_VARIABLE: 937 if (Tcl_TraceVar(interp, Tcl_GetString(objv[2]), 938 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 939 WaitVariableProc, (ClientData) &done) != TCL_OK) { 940 return TCL_ERROR; 941 } 942 done = 0; 943 while (!done) { 944 Tcl_DoOneEvent(0); 945 } 946 Tcl_UntraceVar(interp, Tcl_GetString(objv[2]), 947 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 948 WaitVariableProc, (ClientData) &done); 949 break; 950 951 case TKWAIT_VISIBILITY: { 952 Tk_Window window; 953 954 window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin); 955 if (window == NULL) { 956 return TCL_ERROR; 957 } 958 Tk_CreateEventHandler(window, 959 VisibilityChangeMask|StructureNotifyMask, 960 WaitVisibilityProc, (ClientData) &done); 961 done = 0; 962 while (!done) { 963 Tcl_DoOneEvent(0); 964 } 965 if (done != 1) { 966 /* 967 * Note that we do not delete the event handler because it was 968 * deleted automatically when the window was destroyed. 969 */ 970 971 Tcl_ResetResult(interp); 972 Tcl_AppendResult(interp, "window \"", Tcl_GetString(objv[2]), 973 "\" was deleted before its visibility changed", NULL); 974 return TCL_ERROR; 975 } 976 Tk_DeleteEventHandler(window, 977 VisibilityChangeMask|StructureNotifyMask, 978 WaitVisibilityProc, (ClientData) &done); 979 break; 980 } 981 982 case TKWAIT_WINDOW: { 983 Tk_Window window; 984 985 window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin); 986 if (window == NULL) { 987 return TCL_ERROR; 988 } 989 Tk_CreateEventHandler(window, StructureNotifyMask, 990 WaitWindowProc, (ClientData) &done); 991 done = 0; 992 while (!done) { 993 Tcl_DoOneEvent(0); 994 } 995 996 /* 997 * Note: there's no need to delete the event handler. It was deleted 998 * automatically when the window was destroyed. 999 */ 1000 1001 break; 1002 } 1003 } 1004 1005 /* 1006 * Clear out the interpreter's result, since it may have been set by event 1007 * handlers. 1008 */ 1009 1010 Tcl_ResetResult(interp); 1011 return TCL_OK; 1012} 1013 1014 /* ARGSUSED */ 1015static char * 1016WaitVariableProc( 1017 ClientData clientData, /* Pointer to integer to set to 1. */ 1018 Tcl_Interp *interp, /* Interpreter containing variable. */ 1019 const char *name1, /* Name of variable. */ 1020 const char *name2, /* Second part of variable name. */ 1021 int flags) /* Information about what happened. */ 1022{ 1023 int *donePtr = (int *) clientData; 1024 1025 *donePtr = 1; 1026 return NULL; 1027} 1028 1029 /*ARGSUSED*/ 1030static void 1031WaitVisibilityProc( 1032 ClientData clientData, /* Pointer to integer to set to 1. */ 1033 XEvent *eventPtr) /* Information about event (not used). */ 1034{ 1035 int *donePtr = (int *) clientData; 1036 1037 if (eventPtr->type == VisibilityNotify) { 1038 *donePtr = 1; 1039 } 1040 if (eventPtr->type == DestroyNotify) { 1041 *donePtr = 2; 1042 } 1043} 1044 1045static void 1046WaitWindowProc( 1047 ClientData clientData, /* Pointer to integer to set to 1. */ 1048 XEvent *eventPtr) /* Information about event. */ 1049{ 1050 int *donePtr = (int *) clientData; 1051 1052 if (eventPtr->type == DestroyNotify) { 1053 *donePtr = 1; 1054 } 1055} 1056 1057/* 1058 *---------------------------------------------------------------------- 1059 * 1060 * Tk_UpdateObjCmd -- 1061 * 1062 * This function is invoked to process the "update" Tcl command. See the 1063 * user documentation for details on what it does. 1064 * 1065 * Results: 1066 * A standard Tcl result. 1067 * 1068 * Side effects: 1069 * See the user documentation. 1070 * 1071 *---------------------------------------------------------------------- 1072 */ 1073 1074 /* ARGSUSED */ 1075int 1076Tk_UpdateObjCmd( 1077 ClientData clientData, /* Main window associated with interpreter. */ 1078 Tcl_Interp *interp, /* Current interpreter. */ 1079 int objc, /* Number of arguments. */ 1080 Tcl_Obj *const objv[]) /* Argument objects. */ 1081{ 1082 static const char *updateOptions[] = {"idletasks", NULL}; 1083 int flags, index; 1084 TkDisplay *dispPtr; 1085 1086 if (objc == 1) { 1087 flags = TCL_DONT_WAIT; 1088 } else if (objc == 2) { 1089 if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0, 1090 &index) != TCL_OK) { 1091 return TCL_ERROR; 1092 } 1093 flags = TCL_IDLE_EVENTS; 1094 } else { 1095 Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?"); 1096 return TCL_ERROR; 1097 } 1098 1099 /* 1100 * Handle all pending events, sync all displays, and repeat over and over 1101 * again until all pending events have been handled. Special note: it's 1102 * possible that the entire application could be destroyed by an event 1103 * handler that occurs during the update. Thus, don't use any information 1104 * from tkwin after calling Tcl_DoOneEvent. 1105 */ 1106 1107 while (1) { 1108 while (Tcl_DoOneEvent(flags) != 0) { 1109 /* Empty loop body */ 1110 } 1111 for (dispPtr = TkGetDisplayList(); dispPtr != NULL; 1112 dispPtr = dispPtr->nextPtr) { 1113 XSync(dispPtr->display, False); 1114 } 1115 if (Tcl_DoOneEvent(flags) == 0) { 1116 break; 1117 } 1118 } 1119 1120 /* 1121 * Must clear the interpreter's result because event handlers could have 1122 * executed commands. 1123 */ 1124 1125 Tcl_ResetResult(interp); 1126 return TCL_OK; 1127} 1128 1129/* 1130 *---------------------------------------------------------------------- 1131 * 1132 * Tk_WinfoObjCmd -- 1133 * 1134 * This function is invoked to process the "winfo" Tcl command. See the 1135 * user documentation for details on what it does. 1136 * 1137 * Results: 1138 * A standard Tcl result. 1139 * 1140 * Side effects: 1141 * See the user documentation. 1142 * 1143 *---------------------------------------------------------------------- 1144 */ 1145 1146int 1147Tk_WinfoObjCmd( 1148 ClientData clientData, /* Main window associated with interpreter. */ 1149 Tcl_Interp *interp, /* Current interpreter. */ 1150 int objc, /* Number of arguments. */ 1151 Tcl_Obj *const objv[]) /* Argument objects. */ 1152{ 1153 int index, x, y, width, height, useX, useY, class, skip; 1154 char *string; 1155 TkWindow *winPtr; 1156 Tk_Window tkwin; 1157 Tcl_Obj *resultPtr; 1158 1159 static const TkStateMap visualMap[] = { 1160 {PseudoColor, "pseudocolor"}, 1161 {GrayScale, "grayscale"}, 1162 {DirectColor, "directcolor"}, 1163 {TrueColor, "truecolor"}, 1164 {StaticColor, "staticcolor"}, 1165 {StaticGray, "staticgray"}, 1166 {-1, NULL} 1167 }; 1168 static const char *optionStrings[] = { 1169 "cells", "children", "class", "colormapfull", 1170 "depth", "geometry", "height", "id", 1171 "ismapped", "manager", "name", "parent", 1172 "pointerx", "pointery", "pointerxy", "reqheight", 1173 "reqwidth", "rootx", "rooty", "screen", 1174 "screencells", "screendepth", "screenheight", "screenwidth", 1175 "screenmmheight","screenmmwidth","screenvisual","server", 1176 "toplevel", "viewable", "visual", "visualid", 1177 "vrootheight", "vrootwidth", "vrootx", "vrooty", 1178 "width", "x", "y", 1179 1180 "atom", "atomname", "containing", "interps", 1181 "pathname", 1182 1183 "exists", "fpixels", "pixels", "rgb", 1184 "visualsavailable", 1185 1186 NULL 1187 }; 1188 enum options { 1189 WIN_CELLS, WIN_CHILDREN, WIN_CLASS, WIN_COLORMAPFULL, 1190 WIN_DEPTH, WIN_GEOMETRY, WIN_HEIGHT, WIN_ID, 1191 WIN_ISMAPPED, WIN_MANAGER, WIN_NAME, WIN_PARENT, 1192 WIN_POINTERX, WIN_POINTERY, WIN_POINTERXY, WIN_REQHEIGHT, 1193 WIN_REQWIDTH, WIN_ROOTX, WIN_ROOTY, WIN_SCREEN, 1194 WIN_SCREENCELLS,WIN_SCREENDEPTH,WIN_SCREENHEIGHT,WIN_SCREENWIDTH, 1195 WIN_SCREENMMHEIGHT,WIN_SCREENMMWIDTH,WIN_SCREENVISUAL,WIN_SERVER, 1196 WIN_TOPLEVEL, WIN_VIEWABLE, WIN_VISUAL, WIN_VISUALID, 1197 WIN_VROOTHEIGHT,WIN_VROOTWIDTH, WIN_VROOTX, WIN_VROOTY, 1198 WIN_WIDTH, WIN_X, WIN_Y, 1199 1200 WIN_ATOM, WIN_ATOMNAME, WIN_CONTAINING, WIN_INTERPS, 1201 WIN_PATHNAME, 1202 1203 WIN_EXISTS, WIN_FPIXELS, WIN_PIXELS, WIN_RGB, 1204 WIN_VISUALSAVAILABLE 1205 }; 1206 1207 tkwin = (Tk_Window) clientData; 1208 1209 if (objc < 2) { 1210 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); 1211 return TCL_ERROR; 1212 } 1213 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 1214 &index) != TCL_OK) { 1215 return TCL_ERROR; 1216 } 1217 1218 if (index < WIN_ATOM) { 1219 if (objc != 3) { 1220 Tcl_WrongNumArgs(interp, 2, objv, "window"); 1221 return TCL_ERROR; 1222 } 1223 string = Tcl_GetString(objv[2]); 1224 tkwin = Tk_NameToWindow(interp, string, tkwin); 1225 if (tkwin == NULL) { 1226 return TCL_ERROR; 1227 } 1228 } 1229 winPtr = (TkWindow *) tkwin; 1230 resultPtr = Tcl_GetObjResult(interp); 1231 1232 switch ((enum options) index) { 1233 case WIN_CELLS: 1234 Tcl_SetIntObj(resultPtr, Tk_Visual(tkwin)->map_entries); 1235 break; 1236 case WIN_CHILDREN: { 1237 Tcl_Obj *strPtr; 1238 1239 winPtr = winPtr->childList; 1240 for ( ; winPtr != NULL; winPtr = winPtr->nextPtr) { 1241 if (!(winPtr->flags & TK_ANONYMOUS_WINDOW)) { 1242 strPtr = Tcl_NewStringObj(winPtr->pathName, -1); 1243 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); 1244 } 1245 } 1246 break; 1247 } 1248 case WIN_CLASS: 1249 Tcl_SetStringObj(resultPtr, Tk_Class(tkwin), -1); 1250 break; 1251 case WIN_COLORMAPFULL: 1252 Tcl_SetBooleanObj(resultPtr, 1253 TkpCmapStressed(tkwin, Tk_Colormap(tkwin))); 1254 break; 1255 case WIN_DEPTH: 1256 Tcl_SetIntObj(resultPtr, Tk_Depth(tkwin)); 1257 break; 1258 case WIN_GEOMETRY: { 1259 char buf[16 + TCL_INTEGER_SPACE * 4]; 1260 1261 sprintf(buf, "%dx%d+%d+%d", Tk_Width(tkwin), Tk_Height(tkwin), 1262 Tk_X(tkwin), Tk_Y(tkwin)); 1263 Tcl_SetStringObj(resultPtr, buf, -1); 1264 break; 1265 } 1266 case WIN_HEIGHT: 1267 Tcl_SetIntObj(resultPtr, Tk_Height(tkwin)); 1268 break; 1269 case WIN_ID: { 1270 char buf[TCL_INTEGER_SPACE]; 1271 1272 Tk_MakeWindowExist(tkwin); 1273 TkpPrintWindowId(buf, Tk_WindowId(tkwin)); 1274 1275 /* 1276 * interp result may have changed, refetch it 1277 */ 1278 1279 resultPtr = Tcl_GetObjResult(interp); 1280 Tcl_SetStringObj(resultPtr, buf, -1); 1281 break; 1282 } 1283 case WIN_ISMAPPED: 1284 Tcl_SetBooleanObj(resultPtr, (int) Tk_IsMapped(tkwin)); 1285 break; 1286 case WIN_MANAGER: 1287 if (winPtr->geomMgrPtr != NULL) { 1288 Tcl_SetStringObj(resultPtr, winPtr->geomMgrPtr->name, -1); 1289 } 1290 break; 1291 case WIN_NAME: 1292 Tcl_SetStringObj(resultPtr, Tk_Name(tkwin), -1); 1293 break; 1294 case WIN_PARENT: 1295 if (winPtr->parentPtr != NULL) { 1296 Tcl_SetStringObj(resultPtr, winPtr->parentPtr->pathName, -1); 1297 } 1298 break; 1299 case WIN_POINTERX: 1300 useX = 1; 1301 useY = 0; 1302 goto pointerxy; 1303 case WIN_POINTERY: 1304 useX = 0; 1305 useY = 1; 1306 goto pointerxy; 1307 case WIN_POINTERXY: 1308 useX = 1; 1309 useY = 1; 1310 1311 pointerxy: 1312 winPtr = GetTopHierarchy(tkwin); 1313 if (winPtr == NULL) { 1314 x = -1; 1315 y = -1; 1316 } else { 1317 TkGetPointerCoords((Tk_Window) winPtr, &x, &y); 1318 } 1319 if (useX & useY) { 1320 char buf[TCL_INTEGER_SPACE * 2]; 1321 1322 sprintf(buf, "%d %d", x, y); 1323 Tcl_SetStringObj(resultPtr, buf, -1); 1324 } else if (useX) { 1325 Tcl_SetIntObj(resultPtr, x); 1326 } else { 1327 Tcl_SetIntObj(resultPtr, y); 1328 } 1329 break; 1330 case WIN_REQHEIGHT: 1331 Tcl_SetIntObj(resultPtr, Tk_ReqHeight(tkwin)); 1332 break; 1333 case WIN_REQWIDTH: 1334 Tcl_SetIntObj(resultPtr, Tk_ReqWidth(tkwin)); 1335 break; 1336 case WIN_ROOTX: 1337 Tk_GetRootCoords(tkwin, &x, &y); 1338 Tcl_SetIntObj(resultPtr, x); 1339 break; 1340 case WIN_ROOTY: 1341 Tk_GetRootCoords(tkwin, &x, &y); 1342 Tcl_SetIntObj(resultPtr, y); 1343 break; 1344 case WIN_SCREEN: { 1345 char buf[TCL_INTEGER_SPACE]; 1346 1347 sprintf(buf, "%d", Tk_ScreenNumber(tkwin)); 1348 Tcl_AppendStringsToObj(resultPtr, Tk_DisplayName(tkwin),".",buf, NULL); 1349 break; 1350 } 1351 case WIN_SCREENCELLS: 1352 Tcl_SetIntObj(resultPtr, CellsOfScreen(Tk_Screen(tkwin))); 1353 break; 1354 case WIN_SCREENDEPTH: 1355 Tcl_SetIntObj(resultPtr, DefaultDepthOfScreen(Tk_Screen(tkwin))); 1356 break; 1357 case WIN_SCREENHEIGHT: 1358 Tcl_SetIntObj(resultPtr, HeightOfScreen(Tk_Screen(tkwin))); 1359 break; 1360 case WIN_SCREENWIDTH: 1361 Tcl_SetIntObj(resultPtr, WidthOfScreen(Tk_Screen(tkwin))); 1362 break; 1363 case WIN_SCREENMMHEIGHT: 1364 Tcl_SetIntObj(resultPtr, HeightMMOfScreen(Tk_Screen(tkwin))); 1365 break; 1366 case WIN_SCREENMMWIDTH: 1367 Tcl_SetIntObj(resultPtr, WidthMMOfScreen(Tk_Screen(tkwin))); 1368 break; 1369 case WIN_SCREENVISUAL: 1370 class = DefaultVisualOfScreen(Tk_Screen(tkwin))->class; 1371 goto visual; 1372 case WIN_SERVER: 1373 TkGetServerInfo(interp, tkwin); 1374 break; 1375 case WIN_TOPLEVEL: 1376 winPtr = GetTopHierarchy(tkwin); 1377 if (winPtr != NULL) { 1378 Tcl_SetStringObj(resultPtr, winPtr->pathName, -1); 1379 } 1380 break; 1381 case WIN_VIEWABLE: { 1382 int viewable = 0; 1383 1384 for ( ; ; winPtr = winPtr->parentPtr) { 1385 if ((winPtr == NULL) || !(winPtr->flags & TK_MAPPED)) { 1386 break; 1387 } 1388 if (winPtr->flags & TK_TOP_HIERARCHY) { 1389 viewable = 1; 1390 break; 1391 } 1392 } 1393 1394 Tcl_SetBooleanObj(resultPtr, viewable); 1395 break; 1396 } 1397 case WIN_VISUAL: 1398 class = Tk_Visual(tkwin)->class; 1399 1400 visual: 1401 string = TkFindStateString(visualMap, class); 1402 if (string == NULL) { 1403 string = "unknown"; 1404 } 1405 Tcl_SetStringObj(resultPtr, string, -1); 1406 break; 1407 case WIN_VISUALID: { 1408 char buf[TCL_INTEGER_SPACE]; 1409 1410 sprintf(buf, "0x%x", 1411 (unsigned int) XVisualIDFromVisual(Tk_Visual(tkwin))); 1412 Tcl_SetStringObj(resultPtr, buf, -1); 1413 break; 1414 } 1415 case WIN_VROOTHEIGHT: 1416 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); 1417 Tcl_SetIntObj(resultPtr, height); 1418 break; 1419 case WIN_VROOTWIDTH: 1420 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); 1421 Tcl_SetIntObj(resultPtr, width); 1422 break; 1423 case WIN_VROOTX: 1424 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); 1425 Tcl_SetIntObj(resultPtr, x); 1426 break; 1427 case WIN_VROOTY: 1428 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); 1429 Tcl_SetIntObj(resultPtr, y); 1430 break; 1431 case WIN_WIDTH: 1432 Tcl_SetIntObj(resultPtr, Tk_Width(tkwin)); 1433 break; 1434 case WIN_X: 1435 Tcl_SetIntObj(resultPtr, Tk_X(tkwin)); 1436 break; 1437 case WIN_Y: 1438 Tcl_SetIntObj(resultPtr, Tk_Y(tkwin)); 1439 break; 1440 1441 /* 1442 * Uses -displayof. 1443 */ 1444 1445 case WIN_ATOM: 1446 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 1447 if (skip < 0) { 1448 return TCL_ERROR; 1449 } 1450 if (objc - skip != 3) { 1451 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? name"); 1452 return TCL_ERROR; 1453 } 1454 objv += skip; 1455 string = Tcl_GetString(objv[2]); 1456 Tcl_SetLongObj(resultPtr, (long) Tk_InternAtom(tkwin, string)); 1457 break; 1458 case WIN_ATOMNAME: { 1459 const char *name; 1460 long id; 1461 1462 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 1463 if (skip < 0) { 1464 return TCL_ERROR; 1465 } 1466 if (objc - skip != 3) { 1467 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? id"); 1468 return TCL_ERROR; 1469 } 1470 objv += skip; 1471 if (Tcl_GetLongFromObj(interp, objv[2], &id) != TCL_OK) { 1472 return TCL_ERROR; 1473 } 1474 name = Tk_GetAtomName(tkwin, (Atom) id); 1475 if (strcmp(name, "?bad atom?") == 0) { 1476 string = Tcl_GetString(objv[2]); 1477 Tcl_AppendStringsToObj(resultPtr, 1478 "no atom exists with id \"", string, "\"", NULL); 1479 return TCL_ERROR; 1480 } 1481 Tcl_SetStringObj(resultPtr, name, -1); 1482 break; 1483 } 1484 case WIN_CONTAINING: 1485 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 1486 if (skip < 0) { 1487 return TCL_ERROR; 1488 } 1489 if (objc - skip != 4) { 1490 Tcl_WrongNumArgs(interp, 2, objv, 1491 "?-displayof window? rootX rootY"); 1492 return TCL_ERROR; 1493 } 1494 objv += skip; 1495 string = Tcl_GetString(objv[2]); 1496 if (Tk_GetPixels(interp, tkwin, string, &x) != TCL_OK) { 1497 return TCL_ERROR; 1498 } 1499 string = Tcl_GetString(objv[3]); 1500 if (Tk_GetPixels(interp, tkwin, string, &y) != TCL_OK) { 1501 return TCL_ERROR; 1502 } 1503 tkwin = Tk_CoordsToWindow(x, y, tkwin); 1504 if (tkwin != NULL) { 1505 Tcl_SetStringObj(resultPtr, Tk_PathName(tkwin), -1); 1506 } 1507 break; 1508 case WIN_INTERPS: { 1509 int result; 1510 1511 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 1512 if (skip < 0) { 1513 return TCL_ERROR; 1514 } 1515 if (objc - skip != 2) { 1516 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?"); 1517 return TCL_ERROR; 1518 } 1519 result = TkGetInterpNames(interp, tkwin); 1520 return result; 1521 } 1522 case WIN_PATHNAME: { 1523 Window id; 1524 1525 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 1526 if (skip < 0) { 1527 return TCL_ERROR; 1528 } 1529 if (objc - skip != 3) { 1530 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? id"); 1531 return TCL_ERROR; 1532 } 1533 string = Tcl_GetString(objv[2 + skip]); 1534 if (TkpScanWindowId(interp, string, &id) != TCL_OK) { 1535 return TCL_ERROR; 1536 } 1537 winPtr = (TkWindow *)Tk_IdToWindow(Tk_Display(tkwin), id); 1538 if ((winPtr == NULL) || 1539 (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) { 1540 Tcl_AppendStringsToObj(resultPtr, "window id \"", string, 1541 "\" doesn't exist in this application", NULL); 1542 return TCL_ERROR; 1543 } 1544 1545 /* 1546 * If the window is a utility window with no associated path (such as 1547 * a wrapper window or send communication window), just return an 1548 * empty string. 1549 */ 1550 1551 tkwin = (Tk_Window) winPtr; 1552 if (Tk_PathName(tkwin) != NULL) { 1553 Tcl_SetStringObj(resultPtr, Tk_PathName(tkwin), -1); 1554 } 1555 break; 1556 } 1557 1558 /* 1559 * objv[3] is window. 1560 */ 1561 1562 case WIN_EXISTS: { 1563 int alive; 1564 1565 if (objc != 3) { 1566 Tcl_WrongNumArgs(interp, 2, objv, "window"); 1567 return TCL_ERROR; 1568 } 1569 string = Tcl_GetString(objv[2]); 1570 winPtr = (TkWindow *) Tk_NameToWindow(interp, string, tkwin); 1571 Tcl_ResetResult(interp); 1572 resultPtr = Tcl_GetObjResult(interp); 1573 1574 alive = 1; 1575 if ((winPtr == NULL) || (winPtr->flags & TK_ALREADY_DEAD)) { 1576 alive = 0; 1577 } 1578 Tcl_SetBooleanObj(resultPtr, alive); 1579 break; 1580 } 1581 case WIN_FPIXELS: { 1582 double mm, pixels; 1583 1584 if (objc != 4) { 1585 Tcl_WrongNumArgs(interp, 2, objv, "window number"); 1586 return TCL_ERROR; 1587 } 1588 string = Tcl_GetString(objv[2]); 1589 tkwin = Tk_NameToWindow(interp, string, tkwin); 1590 if (tkwin == NULL) { 1591 return TCL_ERROR; 1592 } 1593 string = Tcl_GetString(objv[3]); 1594 if (Tk_GetScreenMM(interp, tkwin, string, &mm) != TCL_OK) { 1595 return TCL_ERROR; 1596 } 1597 pixels = mm * WidthOfScreen(Tk_Screen(tkwin)) 1598 / WidthMMOfScreen(Tk_Screen(tkwin)); 1599 Tcl_SetDoubleObj(resultPtr, pixels); 1600 break; 1601 } 1602 case WIN_PIXELS: { 1603 int pixels; 1604 1605 if (objc != 4) { 1606 Tcl_WrongNumArgs(interp, 2, objv, "window number"); 1607 return TCL_ERROR; 1608 } 1609 string = Tcl_GetString(objv[2]); 1610 tkwin = Tk_NameToWindow(interp, string, tkwin); 1611 if (tkwin == NULL) { 1612 return TCL_ERROR; 1613 } 1614 string = Tcl_GetString(objv[3]); 1615 if (Tk_GetPixels(interp, tkwin, string, &pixels) != TCL_OK) { 1616 return TCL_ERROR; 1617 } 1618 Tcl_SetIntObj(resultPtr, pixels); 1619 break; 1620 } 1621 case WIN_RGB: { 1622 XColor *colorPtr; 1623 char buf[TCL_INTEGER_SPACE * 3]; 1624 1625 if (objc != 4) { 1626 Tcl_WrongNumArgs(interp, 2, objv, "window colorName"); 1627 return TCL_ERROR; 1628 } 1629 string = Tcl_GetString(objv[2]); 1630 tkwin = Tk_NameToWindow(interp, string, tkwin); 1631 if (tkwin == NULL) { 1632 return TCL_ERROR; 1633 } 1634 string = Tcl_GetString(objv[3]); 1635 colorPtr = Tk_GetColor(interp, tkwin, string); 1636 if (colorPtr == NULL) { 1637 return TCL_ERROR; 1638 } 1639 sprintf(buf, "%d %d %d", colorPtr->red, colorPtr->green, 1640 colorPtr->blue); 1641 Tk_FreeColor(colorPtr); 1642 Tcl_SetStringObj(resultPtr, buf, -1); 1643 break; 1644 } 1645 case WIN_VISUALSAVAILABLE: { 1646 XVisualInfo template, *visInfoPtr; 1647 int count, i; 1648 int includeVisualId; 1649 Tcl_Obj *strPtr; 1650 char buf[16 + TCL_INTEGER_SPACE]; 1651 char visualIdString[TCL_INTEGER_SPACE]; 1652 1653 if (objc == 3) { 1654 includeVisualId = 0; 1655 } else if ((objc == 4) 1656 && (strcmp(Tcl_GetString(objv[3]), "includeids") == 0)) { 1657 includeVisualId = 1; 1658 } else { 1659 Tcl_WrongNumArgs(interp, 2, objv, "window ?includeids?"); 1660 return TCL_ERROR; 1661 } 1662 1663 string = Tcl_GetString(objv[2]); 1664 tkwin = Tk_NameToWindow(interp, string, tkwin); 1665 if (tkwin == NULL) { 1666 return TCL_ERROR; 1667 } 1668 1669 template.screen = Tk_ScreenNumber(tkwin); 1670 visInfoPtr = XGetVisualInfo(Tk_Display(tkwin), VisualScreenMask, 1671 &template, &count); 1672 if (visInfoPtr == NULL) { 1673 Tcl_SetStringObj(resultPtr, 1674 "can't find any visuals for screen", -1); 1675 return TCL_ERROR; 1676 } 1677 for (i = 0; i < count; i++) { 1678 string = TkFindStateString(visualMap, visInfoPtr[i].class); 1679 if (string == NULL) { 1680 strcpy(buf, "unknown"); 1681 } else { 1682 sprintf(buf, "%s %d", string, visInfoPtr[i].depth); 1683 } 1684 if (includeVisualId) { 1685 sprintf(visualIdString, " 0x%x", 1686 (unsigned int) visInfoPtr[i].visualid); 1687 strcat(buf, visualIdString); 1688 } 1689 strPtr = Tcl_NewStringObj(buf, -1); 1690 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); 1691 } 1692 XFree((char *) visInfoPtr); 1693 break; 1694 } 1695 } 1696 return TCL_OK; 1697} 1698 1699#if 0 1700/* 1701 *---------------------------------------------------------------------- 1702 * 1703 * Tk_WmObjCmd -- 1704 * 1705 * This function is invoked to process the "wm" Tcl command. See the user 1706 * documentation for details on what it does. 1707 * 1708 * Results: 1709 * A standard Tcl result. 1710 * 1711 * Side effects: 1712 * See the user documentation. 1713 * 1714 *---------------------------------------------------------------------- 1715 */ 1716 1717 /* ARGSUSED */ 1718int 1719Tk_WmObjCmd( 1720 ClientData clientData, /* Main window associated with interpreter. */ 1721 Tcl_Interp *interp, /* Current interpreter. */ 1722 int objc, /* Number of arguments. */ 1723 Tcl_Obj *const objv[]) /* Argument objects. */ 1724{ 1725 Tk_Window tkwin; 1726 TkWindow *winPtr; 1727 1728 static const char *optionStrings[] = { 1729 "aspect", "client", "command", "deiconify", 1730 "focusmodel", "frame", "geometry", "grid", 1731 "group", "iconbitmap", "iconify", "iconmask", 1732 "iconname", "iconposition", "iconwindow", "maxsize", 1733 "minsize", "overrideredirect", "positionfrom", "protocol", 1734 "resizable", "sizefrom", "state", "title", 1735 "tracing", "transient", "withdraw", NULL 1736 }; 1737 enum options { 1738 TKWM_ASPECT, TKWM_CLIENT, TKWM_COMMAND, TKWM_DEICONIFY, 1739 TKWM_FOCUSMOD, TKWM_FRAME, TKWM_GEOMETRY, TKWM_GRID, 1740 TKWM_GROUP, TKWM_ICONBMP, TKWM_ICONIFY, TKWM_ICONMASK, 1741 TKWM_ICONNAME, TKWM_ICONPOS, TKWM_ICONWIN, TKWM_MAXSIZE, 1742 TKWM_MINSIZE, TKWM_OVERRIDE, TKWM_POSFROM, TKWM_PROTOCOL, 1743 TKWM_RESIZABLE, TKWM_SIZEFROM, TKWM_STATE, TKWM_TITLE, 1744 TKWM_TRACING, TKWM_TRANSIENT, TKWM_WITHDRAW 1745 }; 1746 1747 tkwin = (Tk_Window) clientData; 1748 1749 if (objc < 2) { 1750 Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg?"); 1751 return TCL_ERROR; 1752 } 1753 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 1754 &index) != TCL_OK) { 1755 return TCL_ERROR; 1756 } 1757 1758 if (index == TKWM_TRACING) { 1759 int wmTracing; 1760 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; 1761 1762 if ((objc != 2) && (objc != 3)) { 1763 Tcl_WrongNumArgs(interp, 1, objv, "tracing ?boolean?"); 1764 return TCL_ERROR; 1765 } 1766 if (objc == 2) { 1767 Tcl_SetObjResult(interp, 1768 Tcl_NewBooleanObj(dispPtr->flags & TK_DISPLAY_WM_TRACING)); 1769 return TCL_OK; 1770 } 1771 if (Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing) != TCL_OK) { 1772 return TCL_ERROR; 1773 } 1774 if (wmTracing) { 1775 dispPtr->flags |= TK_DISPLAY_WM_TRACING; 1776 } else { 1777 dispPtr->flags &= ~TK_DISPLAY_WM_TRACING; 1778 } 1779 return TCL_OK; 1780 } 1781 1782 if (objc < 3) { 1783 Tcl_WrongNumArgs(interp, 2, objv, "window ?arg?"); 1784 return TCL_ERROR; 1785 } 1786 1787 winPtr = (TkWindow *) Tk_NameToWindow(interp, 1788 Tcl_GetString(objv[2]), tkwin); 1789 if (winPtr == NULL) { 1790 return TCL_ERROR; 1791 } 1792 if (!(winPtr->flags & TK_TOP_LEVEL)) { 1793 Tcl_AppendResult(interp, "window \"", winPtr->pathName, 1794 "\" isn't a top-level window", NULL); 1795 return TCL_ERROR; 1796 } 1797 1798 switch ((enum options) index) { 1799 case TKWM_ASPECT: 1800 TkpWmAspectCmd(interp, tkwin, winPtr, objc, objv); 1801 break; 1802 case TKWM_CLIENT: 1803 TkpWmClientCmd(interp, tkwin, winPtr, objc, objv); 1804 break; 1805 case TKWM_COMMAND: 1806 TkpWmCommandCmd(interp, tkwin, winPtr, objc, objv); 1807 break; 1808 case TKWM_DEICONIFY: 1809 TkpWmDeiconifyCmd(interp, tkwin, winPtr, objc, objv); 1810 break; 1811 case TKWM_FOCUSMOD: 1812 TkpWmFocusmodCmd(interp, tkwin, winPtr, objc, objv); 1813 break; 1814 case TKWM_FRAME: 1815 TkpWmFrameCmd(interp, tkwin, winPtr, objc, objv); 1816 break; 1817 case TKWM_GEOMETRY: 1818 TkpWmGeometryCmd(interp, tkwin, winPtr, objc, objv); 1819 break; 1820 case TKWM_GRID: 1821 TkpWmGridCmd(interp, tkwin, winPtr, objc, objv); 1822 break; 1823 case TKWM_GROUP: 1824 TkpWmGroupCmd(interp, tkwin, winPtr, objc, objv); 1825 break; 1826 case TKWM_ICONBMP: 1827 TkpWmIconbitmapCmd(interp, tkwin, winPtr, objc, objv); 1828 break; 1829 case TKWM_ICONIFY: 1830 TkpWmIconifyCmd(interp, tkwin, winPtr, objc, objv); 1831 break; 1832 case TKWM_ICONMASK: 1833 TkpWmIconmaskCmd(interp, tkwin, winPtr, objc, objv); 1834 break; 1835 case TKWM_ICONNAME: 1836 /* 1837 * Slight Unix variation. 1838 */ 1839 TkpWmIconnameCmd(interp, tkwin, winPtr, objc, objv); 1840 break; 1841 case TKWM_ICONPOS: 1842 /* 1843 * nearly same - 1 line more on Unix. 1844 */ 1845 TkpWmIconpositionCmd(interp, tkwin, winPtr, objc, objv); 1846 break; 1847 case TKWM_ICONWIN: 1848 TkpWmIconwindowCmd(interp, tkwin, winPtr, objc, objv); 1849 break; 1850 case TKWM_MAXSIZE: 1851 /* 1852 * Nearly same, win diffs. 1853 */ 1854 TkpWmMaxsizeCmd(interp, tkwin, winPtr, objc, objv); 1855 break; 1856 case TKWM_MINSIZE: 1857 /* 1858 * Nearly same, win diffs 1859 */ 1860 TkpWmMinsizeCmd(interp, tkwin, winPtr, objc, objv); 1861 break; 1862 case TKWM_OVERRIDE: 1863 /* 1864 * Almost same. 1865 */ 1866 TkpWmOverrideCmd(interp, tkwin, winPtr, objc, objv); 1867 break; 1868 case TKWM_POSFROM: 1869 /* 1870 * Equal across platforms 1871 */ 1872 TkpWmPositionfromCmd(interp, tkwin, winPtr, objc, objv); 1873 break; 1874 case TKWM_PROTOCOL: 1875 /* 1876 * Equal across platforms 1877 */ 1878 TkpWmProtocolCmd(interp, tkwin, winPtr, objc, objv); 1879 break; 1880 case TKWM_RESIZABLE: 1881 /* 1882 * Almost same 1883 */ 1884 TkpWmResizableCmd(interp, tkwin, winPtr, objc, objv); 1885 break; 1886 case TKWM_SIZEFROM: 1887 /* 1888 * Equal across platforms 1889 */ 1890 TkpWmSizefromCmd(interp, tkwin, winPtr, objc, objv); 1891 break; 1892 case TKWM_STATE: 1893 TkpWmStateCmd(interp, tkwin, winPtr, objc, objv); 1894 break; 1895 case TKWM_TITLE: 1896 TkpWmTitleCmd(interp, tkwin, winPtr, objc, objv); 1897 break; 1898 case TKWM_TRANSIENT: 1899 TkpWmTransientCmd(interp, tkwin, winPtr, objc, objv); 1900 break; 1901 case TKWM_WITHDRAW: 1902 TkpWmWithdrawCmd(interp, tkwin, winPtr, objc, objv); 1903 break; 1904 } 1905 1906 updateGeom: 1907 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 1908 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); 1909 wmPtr->flags |= WM_UPDATE_PENDING; 1910 } 1911 return TCL_OK; 1912} 1913#endif 1914 1915/* 1916 *---------------------------------------------------------------------- 1917 * 1918 * TkGetDisplayOf -- 1919 * 1920 * Parses a "-displayof window" option for various commands. If present, 1921 * the literal "-displayof" should be in objv[0] and the window name in 1922 * objv[1]. 1923 * 1924 * Results: 1925 * The return value is 0 if the argument strings did not contain the 1926 * "-displayof" option. The return value is 2 if the argument strings 1927 * contained both the "-displayof" option and a valid window name. 1928 * Otherwise, the return value is -1 if the window name was missing or 1929 * did not specify a valid window. 1930 * 1931 * If the return value was 2, *tkwinPtr is filled with the token for the 1932 * window specified on the command line. If the return value was -1, an 1933 * error message is left in interp's result object. 1934 * 1935 * Side effects: 1936 * None. 1937 * 1938 *---------------------------------------------------------------------- 1939 */ 1940 1941int 1942TkGetDisplayOf( 1943 Tcl_Interp *interp, /* Interpreter for error reporting. */ 1944 int objc, /* Number of arguments. */ 1945 Tcl_Obj *const objv[], /* Argument objects. If it is present, 1946 * "-displayof" should be in objv[0] and 1947 * objv[1] the name of a window. */ 1948 Tk_Window *tkwinPtr) /* On input, contains main window of 1949 * application associated with interp. On 1950 * output, filled with window specified as 1951 * option to "-displayof" argument, or 1952 * unmodified if "-displayof" argument was not 1953 * present. */ 1954{ 1955 char *string; 1956 int length; 1957 1958 if (objc < 1) { 1959 return 0; 1960 } 1961 string = Tcl_GetStringFromObj(objv[0], &length); 1962 if ((length >= 2) && 1963 (strncmp(string, "-displayof", (unsigned) length) == 0)) { 1964 if (objc < 2) { 1965 Tcl_SetStringObj(Tcl_GetObjResult(interp), 1966 "value for \"-displayof\" missing", -1); 1967 return -1; 1968 } 1969 *tkwinPtr = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), *tkwinPtr); 1970 if (*tkwinPtr == NULL) { 1971 return -1; 1972 } 1973 return 2; 1974 } 1975 return 0; 1976} 1977 1978/* 1979 *---------------------------------------------------------------------- 1980 * 1981 * TkDeadAppCmd -- 1982 * 1983 * If an application has been deleted then all Tk commands will be 1984 * re-bound to this function. 1985 * 1986 * Results: 1987 * A standard Tcl error is reported to let the user know that the 1988 * application is dead. 1989 * 1990 * Side effects: 1991 * See the user documentation. 1992 * 1993 *---------------------------------------------------------------------- 1994 */ 1995 1996 /* ARGSUSED */ 1997int 1998TkDeadAppCmd( 1999 ClientData clientData, /* Dummy. */ 2000 Tcl_Interp *interp, /* Current interpreter. */ 2001 int argc, /* Number of arguments. */ 2002 const char **argv) /* Argument strings. */ 2003{ 2004 Tcl_AppendResult(interp, "can't invoke \"", argv[0], 2005 "\" command: application has been destroyed", NULL); 2006 return TCL_ERROR; 2007} 2008 2009/* 2010 *---------------------------------------------------------------------- 2011 * 2012 * GetTopHierarchy -- 2013 * 2014 * Retrieves the top-of-hierarchy window which is the nearest ancestor of 2015 * the specified window. 2016 * 2017 * Results: 2018 * Returns the top-of-hierarchy window, or NULL if the window has no 2019 * ancestor which is at the top of a physical window hierarchy. 2020 * 2021 * Side effects: 2022 * None. 2023 * 2024 *---------------------------------------------------------------------- 2025 */ 2026 2027static TkWindow * 2028GetTopHierarchy( 2029 Tk_Window tkwin) /* Window for which the top-of-hierarchy 2030 * ancestor should be deterined. */ 2031{ 2032 TkWindow *winPtr = (TkWindow *) tkwin; 2033 2034 while ((winPtr != NULL) && !(winPtr->flags & TK_TOP_HIERARCHY)) { 2035 winPtr = winPtr->parentPtr; 2036 } 2037 return winPtr; 2038} 2039 2040/* 2041 * Local Variables: 2042 * mode: c 2043 * c-basic-offset: 4 2044 * fill-column: 78 2045 * End: 2046 */ 2047