1/* 2 * tkFrame.c -- 3 * 4 * This module implements "frame", "labelframe" and "toplevel" widgets 5 * for the Tk toolkit. Frames are windows with a background color and 6 * possibly a 3-D effect, but not much else in the way of attributes. 7 * 8 * Copyright (c) 1990-1994 The Regents of the University of California. 9 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 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 "default.h" 18#include "tkInt.h" 19 20/* 21 * The following enum is used to define the type of the frame. 22 */ 23 24enum FrameType { 25 TYPE_FRAME, TYPE_TOPLEVEL, TYPE_LABELFRAME 26}; 27 28/* 29 * A data structure of the following type is kept for each 30 * frame that currently exists for this process: 31 */ 32 33typedef struct { 34 Tk_Window tkwin; /* Window that embodies the frame. NULL means 35 * that the window has been destroyed but the 36 * data structures haven't yet been cleaned 37 * up. */ 38 Display *display; /* Display containing widget. Used, among 39 * other things, so that resources can be 40 * freed even after tkwin has gone away. */ 41 Tcl_Interp *interp; /* Interpreter associated with widget. Used to 42 * delete widget command. */ 43 Tcl_Command widgetCmd; /* Token for frame's widget command. */ 44 Tk_OptionTable optionTable; /* Table that defines configuration options 45 * available for this widget. */ 46 char *className; /* Class name for widget (from configuration 47 * option). Malloc-ed. */ 48 enum FrameType type; /* Type of widget, such as TYPE_FRAME. */ 49 char *screenName; /* Screen on which widget is created. Non-null 50 * only for top-levels. Malloc-ed, may be 51 * NULL. */ 52 char *visualName; /* Textual description of visual for window, 53 * from -visual option. Malloc-ed, may be 54 * NULL. */ 55 char *colormapName; /* Textual description of colormap for window, 56 * from -colormap option. Malloc-ed, may be 57 * NULL. */ 58 char *menuName; /* Textual description of menu to use for 59 * menubar. Malloc-ed, may be NULL. */ 60 Colormap colormap; /* If not None, identifies a colormap 61 * allocated for this window, which must be 62 * freed when the window is deleted. */ 63 Tk_3DBorder border; /* Structure used to draw 3-D border and 64 * background. NULL means no background or 65 * border. */ 66 int borderWidth; /* Width of 3-D border (if any). */ 67 int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ 68 int highlightWidth; /* Width in pixels of highlight to draw around 69 * widget when it has the focus. 0 means don't 70 * draw a highlight. */ 71 XColor *highlightBgColorPtr; 72 /* Color for drawing traversal highlight area 73 * when highlight is off. */ 74 XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ 75 int width; /* Width to request for window. <= 0 means 76 * don't request any size. */ 77 int height; /* Height to request for window. <= 0 means 78 * don't request any size. */ 79 Tk_Cursor cursor; /* Current cursor for window, or None. */ 80 char *takeFocus; /* Value of -takefocus option; not used in the 81 * C code, but used by keyboard traversal 82 * scripts. Malloc'ed, but may be NULL. */ 83 int isContainer; /* 1 means this window is a container, 0 means 84 * that it isn't. */ 85 char *useThis; /* If the window is embedded, this points to 86 * the name of the window in which it is 87 * embedded (malloc'ed). For non-embedded 88 * windows this is NULL. */ 89 int flags; /* Various flags; see below for 90 * definitions. */ 91 Tcl_Obj *padXPtr; /* Value of -padx option: specifies how many 92 * pixels of extra space to leave on left and 93 * right of child area. */ 94 int padX; /* Integer value corresponding to padXPtr. */ 95 Tcl_Obj *padYPtr; /* Value of -padx option: specifies how many 96 * pixels of extra space to leave above and 97 * below child area. */ 98 int padY; /* Integer value corresponding to padYPtr. */ 99} Frame; 100 101/* 102 * A data structure of the following type is kept for each labelframe widget 103 * managed by this file: 104 */ 105 106typedef struct { 107 Frame frame; /* A pointer to the generic frame structure. 108 * This must be the first element of the 109 * Labelframe. */ 110 /* 111 * Labelframe specific configuration settings. 112 */ 113 Tcl_Obj *textPtr; /* Value of -text option: specifies text to 114 * display in button. */ 115 Tk_Font tkfont; /* Value of -font option: specifies font to 116 * use for display text. */ 117 XColor *textColorPtr; /* Value of -fg option: specifies foreground 118 * color in normal mode. */ 119 int labelAnchor; /* Value of -labelanchor option: specifies 120 * where to place the label. */ 121 Tk_Window labelWin; /* Value of -labelwidget option: Window to use 122 * as label for the frame. */ 123 /* 124 * Labelframe specific fields for use with configuration settings above. 125 */ 126 GC textGC; /* GC for drawing text in normal mode. */ 127 Tk_TextLayout textLayout; /* Stored text layout information. */ 128 XRectangle labelBox; /* The label's actual size and position. */ 129 int labelReqWidth; /* The label's requested width. */ 130 int labelReqHeight; /* The label's requested height. */ 131 int labelTextX, labelTextY; /* Position of the text to be drawn. */ 132} Labelframe; 133 134/* 135 * The following macros define how many extra pixels to leave around a label's 136 * text. 137 */ 138 139#define LABELSPACING 1 140#define LABELMARGIN 4 141 142/* 143 * Flag bits for frames: 144 * 145 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has 146 * already been queued to redraw this window. 147 * GOT_FOCUS: Non-zero means this widget currently has the 148 * input focus. 149 */ 150 151#define REDRAW_PENDING 1 152#define GOT_FOCUS 4 153 154/* 155 * The following enum is used to define a type for the -labelanchor option of 156 * the Labelframe widget. These values are used as indices into the string 157 * table below. 158 */ 159 160enum labelanchor { 161 LABELANCHOR_E, LABELANCHOR_EN, LABELANCHOR_ES, 162 LABELANCHOR_N, LABELANCHOR_NE, LABELANCHOR_NW, 163 LABELANCHOR_S, LABELANCHOR_SE, LABELANCHOR_SW, 164 LABELANCHOR_W, LABELANCHOR_WN, LABELANCHOR_WS 165}; 166 167static char *labelAnchorStrings[] = { 168 "e", "en", "es", "n", "ne", "nw", "s", "se", "sw", "w", "wn", "ws", 169 NULL 170}; 171 172/* 173 * Information used for parsing configuration options. There are one common 174 * table used by all and one table for each widget class. 175 */ 176 177static const Tk_OptionSpec commonOptSpec[] = { 178 {TK_OPTION_BORDER, "-background", "background", "Background", 179 DEF_FRAME_BG_COLOR, -1, Tk_Offset(Frame, border), 180 TK_OPTION_NULL_OK, (ClientData) DEF_FRAME_BG_MONO, 0}, 181 {TK_OPTION_SYNONYM, "-bg", NULL, NULL, 182 NULL, 0, -1, 0, (ClientData) "-background", 0}, 183 {TK_OPTION_STRING, "-colormap", "colormap", "Colormap", 184 DEF_FRAME_COLORMAP, -1, Tk_Offset(Frame, colormapName), 185 TK_OPTION_NULL_OK, 0, 0}, 186 {TK_OPTION_BOOLEAN, "-container", "container", "Container", 187 DEF_FRAME_CONTAINER, -1, Tk_Offset(Frame, isContainer), 0, 0, 0}, 188 {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", 189 DEF_FRAME_CURSOR, -1, Tk_Offset(Frame, cursor), 190 TK_OPTION_NULL_OK, 0, 0}, 191 {TK_OPTION_PIXELS, "-height", "height", "Height", 192 DEF_FRAME_HEIGHT, -1, Tk_Offset(Frame, height), 0, 0, 0}, 193 {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", 194 "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG, -1, 195 Tk_Offset(Frame, highlightBgColorPtr), 0, 0, 0}, 196 {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", 197 DEF_FRAME_HIGHLIGHT, -1, Tk_Offset(Frame, highlightColorPtr), 198 0, 0, 0}, 199 {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", 200 "HighlightThickness", DEF_FRAME_HIGHLIGHT_WIDTH, -1, 201 Tk_Offset(Frame, highlightWidth), 0, 0, 0}, 202 {TK_OPTION_PIXELS, "-padx", "padX", "Pad", 203 DEF_FRAME_PADX, Tk_Offset(Frame, padXPtr), 204 Tk_Offset(Frame, padX), 0, 0, 0}, 205 {TK_OPTION_PIXELS, "-pady", "padY", "Pad", 206 DEF_FRAME_PADY, Tk_Offset(Frame, padYPtr), 207 Tk_Offset(Frame, padY), 0, 0, 0}, 208 {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", 209 DEF_FRAME_TAKE_FOCUS, -1, Tk_Offset(Frame, takeFocus), 210 TK_OPTION_NULL_OK, 0, 0}, 211 {TK_OPTION_STRING, "-visual", "visual", "Visual", 212 DEF_FRAME_VISUAL, -1, Tk_Offset(Frame, visualName), 213 TK_OPTION_NULL_OK, 0, 0}, 214 {TK_OPTION_PIXELS, "-width", "width", "Width", 215 DEF_FRAME_WIDTH, -1, Tk_Offset(Frame, width), 0, 0, 0}, 216 {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0} 217}; 218 219static const Tk_OptionSpec frameOptSpec[] = { 220 {TK_OPTION_SYNONYM, "-bd", NULL, NULL, 221 NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, 222 {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", 223 DEF_FRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth), 0, 0, 0}, 224 {TK_OPTION_STRING, "-class", "class", "Class", 225 DEF_FRAME_CLASS, -1, Tk_Offset(Frame, className), 0, 0, 0}, 226 {TK_OPTION_RELIEF, "-relief", "relief", "Relief", 227 DEF_FRAME_RELIEF, -1, Tk_Offset(Frame, relief), 0, 0, 0}, 228 {TK_OPTION_END, NULL, NULL, NULL, 229 NULL, 0, 0, 0, (ClientData) commonOptSpec, 0} 230}; 231 232static const Tk_OptionSpec toplevelOptSpec[] = { 233 {TK_OPTION_SYNONYM, "-bd", NULL, NULL, 234 NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, 235 {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", 236 DEF_FRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth), 0, 0, 0}, 237 {TK_OPTION_STRING, "-class", "class", "Class", 238 DEF_TOPLEVEL_CLASS, -1, Tk_Offset(Frame, className), 0, 0, 0}, 239 {TK_OPTION_STRING, "-menu", "menu", "Menu", 240 DEF_TOPLEVEL_MENU, -1, Tk_Offset(Frame, menuName), 241 TK_OPTION_NULL_OK, 0, 0}, 242 {TK_OPTION_RELIEF, "-relief", "relief", "Relief", 243 DEF_FRAME_RELIEF, -1, Tk_Offset(Frame, relief), 0, 0, 0}, 244 {TK_OPTION_STRING, "-screen", "screen", "Screen", 245 DEF_TOPLEVEL_SCREEN, -1, Tk_Offset(Frame, screenName), 246 TK_OPTION_NULL_OK, 0, 0}, 247 {TK_OPTION_STRING, "-use", "use", "Use", 248 DEF_TOPLEVEL_USE, -1, Tk_Offset(Frame, useThis), 249 TK_OPTION_NULL_OK, 0, 0}, 250 {TK_OPTION_END, NULL, NULL, NULL, 251 NULL, 0, 0, 0, (ClientData) commonOptSpec, 0} 252}; 253 254static const Tk_OptionSpec labelframeOptSpec[] = { 255 {TK_OPTION_SYNONYM, "-bd", NULL, NULL, 256 NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, 257 {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", 258 DEF_LABELFRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth), 259 0, 0, 0}, 260 {TK_OPTION_STRING, "-class", "class", "Class", 261 DEF_LABELFRAME_CLASS, -1, Tk_Offset(Frame, className), 0, 0, 0}, 262 {TK_OPTION_SYNONYM, "-fg", "foreground", NULL, 263 NULL, 0, -1, 0, (ClientData) "-foreground", 0}, 264 {TK_OPTION_FONT, "-font", "font", "Font", 265 DEF_LABELFRAME_FONT, -1, Tk_Offset(Labelframe, tkfont), 0, 0, 0}, 266 {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", 267 DEF_LABELFRAME_FG, -1, Tk_Offset(Labelframe, textColorPtr), 0, 0, 0}, 268 {TK_OPTION_STRING_TABLE, "-labelanchor", "labelAnchor", "LabelAnchor", 269 DEF_LABELFRAME_LABELANCHOR, -1, Tk_Offset(Labelframe, labelAnchor), 270 0, (ClientData) labelAnchorStrings, 0}, 271 {TK_OPTION_WINDOW, "-labelwidget", "labelWidget", "LabelWidget", 272 NULL, -1, Tk_Offset(Labelframe, labelWin), TK_OPTION_NULL_OK, 0, 0}, 273 {TK_OPTION_RELIEF, "-relief", "relief", "Relief", 274 DEF_LABELFRAME_RELIEF, -1, Tk_Offset(Frame, relief), 0, 0, 0}, 275 {TK_OPTION_STRING, "-text", "text", "Text", 276 DEF_LABELFRAME_TEXT, Tk_Offset(Labelframe, textPtr), -1, 277 TK_OPTION_NULL_OK, 0, 0}, 278 {TK_OPTION_END, NULL, NULL, NULL, 279 NULL, 0, 0, 0, (ClientData) commonOptSpec, 0} 280}; 281 282/* 283 * Class names for widgets, indexed by FrameType. 284 */ 285 286static char *classNames[] = {"Frame", "Toplevel", "Labelframe"}; 287 288/* 289 * The following table maps from FrameType to the option template for that 290 * class of widgets. 291 */ 292 293static const Tk_OptionSpec * const optionSpecs[] = { 294 frameOptSpec, 295 toplevelOptSpec, 296 labelframeOptSpec, 297}; 298 299/* 300 * Forward declarations for functions defined later in this file: 301 */ 302 303static void ComputeFrameGeometry(Frame *framePtr); 304static int ConfigureFrame(Tcl_Interp *interp, Frame *framePtr, 305 int objc, Tcl_Obj *CONST objv[]); 306static int CreateFrame(ClientData clientData, Tcl_Interp *interp, 307 int objc, Tcl_Obj *CONST argv[], 308 enum FrameType type, char *appName); 309static void DestroyFrame(char *memPtr); 310static void DestroyFramePartly(Frame *framePtr); 311static void DisplayFrame(ClientData clientData); 312static void FrameCmdDeletedProc(ClientData clientData); 313static void FrameEventProc(ClientData clientData, 314 XEvent *eventPtr); 315static void FrameLostSlaveProc(ClientData clientData, 316 Tk_Window tkwin); 317static void FrameRequestProc(ClientData clientData, 318 Tk_Window tkwin); 319static void FrameStructureProc(ClientData clientData, 320 XEvent *eventPtr); 321static int FrameWidgetObjCmd(ClientData clientData, 322 Tcl_Interp *interp, int objc, 323 Tcl_Obj *CONST objv[]); 324static void FrameWorldChanged(ClientData instanceData); 325static void MapFrame(ClientData clientData); 326 327/* 328 * The structure below defines frame class behavior by means of functions that 329 * can be invoked from generic window code. 330 */ 331 332static Tk_ClassProcs frameClass = { 333 sizeof(Tk_ClassProcs), /* size */ 334 FrameWorldChanged /* worldChangedProc */ 335}; 336 337/* 338 * The structure below defines the official type record for the labelframe's 339 * geometry manager: 340 */ 341 342static const Tk_GeomMgr frameGeomType = { 343 "labelframe", /* name */ 344 FrameRequestProc, /* requestProc */ 345 FrameLostSlaveProc /* lostSlaveProc */ 346}; 347 348/* 349 *-------------------------------------------------------------- 350 * 351 * Tk_FrameObjCmd, Tk_ToplevelObjCmd, Tk_LabelframeObjCmd -- 352 * 353 * These functions are invoked to process the "frame", "toplevel" and 354 * "labelframe" Tcl commands. See the user documentation for details on 355 * what they do. 356 * 357 * Results: 358 * A standard Tcl result. 359 * 360 * Side effects: 361 * See the user documentation. These functions are just wrappers; they 362 * call CreateFrame to do all of the real work. 363 * 364 *-------------------------------------------------------------- 365 */ 366 367int 368Tk_FrameObjCmd( 369 ClientData clientData, /* Either NULL or pointer to option table. */ 370 Tcl_Interp *interp, /* Current interpreter. */ 371 int objc, /* Number of arguments. */ 372 Tcl_Obj *CONST objv[]) /* Argument objects. */ 373{ 374 return CreateFrame(clientData, interp, objc, objv, TYPE_FRAME, NULL); 375} 376 377int 378Tk_ToplevelObjCmd( 379 ClientData clientData, /* Either NULL or pointer to option table. */ 380 Tcl_Interp *interp, /* Current interpreter. */ 381 int objc, /* Number of arguments. */ 382 Tcl_Obj *CONST objv[]) /* Argument objects. */ 383{ 384 return CreateFrame(clientData, interp, objc, objv, TYPE_TOPLEVEL, NULL); 385} 386 387int 388Tk_LabelframeObjCmd( 389 ClientData clientData, /* Either NULL or pointer to option table. */ 390 Tcl_Interp *interp, /* Current interpreter. */ 391 int objc, /* Number of arguments. */ 392 Tcl_Obj *CONST objv[]) /* Argument objects. */ 393{ 394 return CreateFrame(clientData, interp, objc, objv, TYPE_LABELFRAME, NULL); 395} 396 397/* 398 *-------------------------------------------------------------- 399 * 400 * TkCreateFrame -- 401 * 402 * This function is the old command function for the "frame" and 403 * "toplevel" commands. Now it is used directly by Tk_Init to create a 404 * new main window. See the user documentation for the "frame" and 405 * "toplevel" commands for details on what it does. 406 * 407 * Results: 408 * A standard Tcl result. 409 * 410 * Side effects: 411 * See the user documentation. 412 * 413 *-------------------------------------------------------------- 414 */ 415 416int 417TkCreateFrame( 418 ClientData clientData, /* Either NULL or pointer to option table. */ 419 Tcl_Interp *interp, /* Current interpreter. */ 420 int argc, /* Number of arguments. */ 421 char **argv, /* Argument strings. */ 422 int toplevel, /* Non-zero means create a toplevel window, 423 * zero means create a frame. */ 424 char *appName) /* Should only be non-NULL if there is no main 425 * window associated with the interpreter. 426 * Gives the base name to use for the new 427 * application. */ 428{ 429 int result, i; 430 Tcl_Obj **objv = (Tcl_Obj **) ckalloc((argc+1) * sizeof(Tcl_Obj **)); 431 432 for (i=0; i<argc; i++) { 433 objv[i] = Tcl_NewStringObj(argv[i], -1); 434 Tcl_IncrRefCount(objv[i]); 435 } 436 objv[argc] = NULL; 437 result = CreateFrame(clientData, interp, argc, objv, 438 toplevel ? TYPE_TOPLEVEL : TYPE_FRAME, appName); 439 for (i=0; i<argc; i++) { 440 Tcl_DecrRefCount(objv[i]); 441 } 442 ckfree((char *) objv); 443 return result; 444} 445 446static int 447CreateFrame( 448 ClientData clientData, /* NULL. */ 449 Tcl_Interp *interp, /* Current interpreter. */ 450 int objc, /* Number of arguments. */ 451 Tcl_Obj *CONST objv[], /* Argument objects. */ 452 enum FrameType type, /* What widget type to create. */ 453 char *appName) /* Should only be non-NULL if there are no 454 * Main window associated with the 455 * interpreter. Gives the base name to use for 456 * the new application. */ 457{ 458 Tk_Window tkwin; 459 Frame *framePtr; 460 Tk_OptionTable optionTable; 461 Tk_Window newWin; 462 CONST char *className, *screenName, *visualName, *colormapName, *arg, *useOption; 463 int i, c, length, depth; 464 unsigned int mask; 465 Colormap colormap; 466 Visual *visual; 467 468 if (objc < 2) { 469 Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); 470 return TCL_ERROR; 471 } 472 473 /* 474 * Create the option table for this widget class. If it has already been 475 * created, the cached pointer will be returned. 476 */ 477 478 optionTable = Tk_CreateOptionTable(interp, optionSpecs[type]); 479 480 /* 481 * Pre-process the argument list. Scan through it to find any "-class", 482 * "-screen", "-visual", and "-colormap" options. These arguments need to 483 * be processed specially, before the window is configured using the usual 484 * Tk mechanisms. 485 */ 486 487 className = colormapName = screenName = visualName = useOption = NULL; 488 colormap = None; 489 for (i = 2; i < objc; i += 2) { 490 arg = Tcl_GetStringFromObj(objv[i], &length); 491 if (length < 2) { 492 continue; 493 } 494 c = arg[1]; 495 if ((c == 'c') && (length >= 3) 496 && (strncmp(arg, "-class", (unsigned) length) == 0)) { 497 className = Tcl_GetString(objv[i+1]); 498 } else if ((c == 'c') 499 && (strncmp(arg, "-colormap", (unsigned) length) == 0)) { 500 colormapName = Tcl_GetString(objv[i+1]); 501 } else if ((c == 's') && (type == TYPE_TOPLEVEL) 502 && (strncmp(arg, "-screen", (unsigned) length) == 0)) { 503 screenName = Tcl_GetString(objv[i+1]); 504 } else if ((c == 'u') && (type == TYPE_TOPLEVEL) 505 && (strncmp(arg, "-use", (unsigned) length) == 0)) { 506 useOption = Tcl_GetString(objv[i+1]); 507 } else if ((c == 'v') 508 && (strncmp(arg, "-visual", (unsigned) length) == 0)) { 509 visualName = Tcl_GetString(objv[i+1]); 510 } 511 } 512 513 /* 514 * Create the window, and deal with the special options -use, -classname, 515 * -colormap, -screenname, and -visual. These options must be handle 516 * before calling ConfigureFrame below, and they must also be processed in 517 * a particular order, for the following reasons: 518 * 1. Must set the window's class before calling ConfigureFrame, so that 519 * unspecified options are looked up in the option database using the 520 * correct class. 521 * 2. Must set visual information before calling ConfigureFrame so that 522 * colors are allocated in a proper colormap. 523 * 3. Must call TkpUseWindow before setting non-default visual 524 * information, since TkpUseWindow changes the defaults. 525 */ 526 527 if (screenName == NULL) { 528 screenName = (type == TYPE_TOPLEVEL) ? "" : NULL; 529 } 530 531 /* 532 * Main window associated with interpreter. If we're called by Tk_Init to 533 * create a new application, then this is NULL. 534 */ 535 536 tkwin = Tk_MainWindow(interp); 537 if (tkwin != NULL) { 538 newWin = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), 539 screenName); 540 } else if (appName == NULL) { 541 /* 542 * This occurs when someone tried to create a frame/toplevel while we 543 * are being destroyed. Let an error be thrown. 544 */ 545 546 Tcl_AppendResult(interp, "unable to create widget \"", 547 Tcl_GetString(objv[1]), "\"", NULL); 548 newWin = NULL; 549 } else { 550 /* 551 * We were called from Tk_Init; create a new application. 552 */ 553 554 newWin = TkCreateMainWindow(interp, screenName, appName); 555 } 556 if (newWin == NULL) { 557 goto error; 558 } else { 559 /* 560 * Mark Tk frames as suitable candidates for [wm manage] 561 */ 562 TkWindow *winPtr = (TkWindow *)newWin; 563 winPtr->flags |= TK_WM_MANAGEABLE; 564 } 565 if (className == NULL) { 566 className = Tk_GetOption(newWin, "class", "Class"); 567 if (className == NULL) { 568 className = classNames[type]; 569 } 570 } 571 Tk_SetClass(newWin, className); 572 if (useOption == NULL) { 573 useOption = Tk_GetOption(newWin, "use", "Use"); 574 } 575 if ((useOption != NULL) && (*useOption != 0)) { 576 if (TkpUseWindow(interp, newWin, useOption) != TCL_OK) { 577 goto error; 578 } 579 } 580 if (visualName == NULL) { 581 visualName = Tk_GetOption(newWin, "visual", "Visual"); 582 } 583 if (colormapName == NULL) { 584 colormapName = Tk_GetOption(newWin, "colormap", "Colormap"); 585 } 586 if ((colormapName != NULL) && (*colormapName == 0)) { 587 colormapName = NULL; 588 } 589 if (visualName != NULL) { 590 visual = Tk_GetVisual(interp, newWin, visualName, &depth, 591 (colormapName == NULL) ? &colormap : NULL); 592 if (visual == NULL) { 593 goto error; 594 } 595 Tk_SetWindowVisual(newWin, visual, depth, colormap); 596 } 597 if (colormapName != NULL) { 598 colormap = Tk_GetColormap(interp, newWin, colormapName); 599 if (colormap == None) { 600 goto error; 601 } 602 Tk_SetWindowColormap(newWin, colormap); 603 } 604 605 /* 606 * For top-level windows, provide an initial geometry request of 200x200, 607 * just so the window looks nicer on the screen if it doesn't request a 608 * size for itself. 609 */ 610 611 if (type == TYPE_TOPLEVEL) { 612 Tk_GeometryRequest(newWin, 200, 200); 613 } 614 615 /* 616 * Create the widget record, process configuration options, and create 617 * event handlers. Then fill in a few additional fields in the widget 618 * record from the special options. 619 */ 620 621 if (type == TYPE_LABELFRAME) { 622 framePtr = (Frame *) ckalloc(sizeof(Labelframe)); 623 memset((void *) framePtr, 0, (sizeof(Labelframe))); 624 } else { 625 framePtr = (Frame *) ckalloc(sizeof(Frame)); 626 memset((void *) framePtr, 0, (sizeof(Frame))); 627 } 628 framePtr->tkwin = newWin; 629 framePtr->display = Tk_Display(newWin); 630 framePtr->interp = interp; 631 framePtr->widgetCmd = Tcl_CreateObjCommand(interp, 632 Tk_PathName(newWin), FrameWidgetObjCmd, 633 (ClientData) framePtr, FrameCmdDeletedProc); 634 framePtr->optionTable = optionTable; 635 framePtr->type = type; 636 framePtr->colormap = colormap; 637 framePtr->relief = TK_RELIEF_FLAT; 638 framePtr->cursor = None; 639 640 if (framePtr->type == TYPE_LABELFRAME) { 641 Labelframe *labelframePtr = (Labelframe *) framePtr; 642 labelframePtr->labelAnchor = LABELANCHOR_NW; 643 labelframePtr->textGC = None; 644 } 645 646 /* 647 * Store backreference to frame widget in window structure. 648 */ 649 650 Tk_SetClassProcs(newWin, &frameClass, (ClientData) framePtr); 651 652 mask = ExposureMask | StructureNotifyMask | FocusChangeMask; 653 if (type == TYPE_TOPLEVEL) { 654 mask |= ActivateMask; 655 } 656 Tk_CreateEventHandler(newWin, mask, FrameEventProc, (ClientData) framePtr); 657 if ((Tk_InitOptions(interp, (char *) framePtr, optionTable, newWin) 658 != TCL_OK) || 659 (ConfigureFrame(interp, framePtr, objc-2, objv+2) != TCL_OK)) { 660 goto error; 661 } 662 if ((framePtr->isContainer)) { 663 if (framePtr->useThis == NULL) { 664 TkpMakeContainer(framePtr->tkwin); 665 } else { 666 Tcl_AppendResult(interp, "A window cannot have both the -use ", 667 "and the -container option set.", NULL); 668 goto error; 669 } 670 } 671 if (type == TYPE_TOPLEVEL) { 672 Tcl_DoWhenIdle(MapFrame, (ClientData) framePtr); 673 } 674 Tcl_SetResult(interp, Tk_PathName(newWin), TCL_STATIC); 675 return TCL_OK; 676 677 error: 678 if (newWin != NULL) { 679 Tk_DestroyWindow(newWin); 680 } 681 return TCL_ERROR; 682} 683 684/* 685 *-------------------------------------------------------------- 686 * 687 * FrameWidgetObjCmd -- 688 * 689 * This function is invoked to process the Tcl command that corresponds 690 * to a frame widget. See the user documentation for details on what it 691 * does. 692 * 693 * Results: 694 * A standard Tcl result. 695 * 696 * Side effects: 697 * See the user documentation. 698 * 699 *-------------------------------------------------------------- 700 */ 701 702static int 703FrameWidgetObjCmd( 704 ClientData clientData, /* Information about frame widget. */ 705 Tcl_Interp *interp, /* Current interpreter. */ 706 int objc, /* Number of arguments. */ 707 Tcl_Obj *CONST objv[]) /* Argument objects. */ 708{ 709 static CONST char *frameOptions[] = { 710 "cget", "configure", NULL 711 }; 712 enum options { 713 FRAME_CGET, FRAME_CONFIGURE 714 }; 715 register Frame *framePtr = (Frame *) clientData; 716 int result = TCL_OK, index; 717 int c, i, length; 718 Tcl_Obj *objPtr; 719 720 if (objc < 2) { 721 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); 722 return TCL_ERROR; 723 } 724 if (Tcl_GetIndexFromObj(interp, objv[1], frameOptions, "option", 0, 725 &index) != TCL_OK) { 726 return TCL_ERROR; 727 } 728 Tcl_Preserve((ClientData) framePtr); 729 switch ((enum options) index) { 730 case FRAME_CGET: 731 if (objc != 3) { 732 Tcl_WrongNumArgs(interp, 2, objv, "option"); 733 result = TCL_ERROR; 734 goto done; 735 } 736 objPtr = Tk_GetOptionValue(interp, (char *) framePtr, 737 framePtr->optionTable, objv[2], framePtr->tkwin); 738 if (objPtr == NULL) { 739 result = TCL_ERROR; 740 goto done; 741 } else { 742 Tcl_SetObjResult(interp, objPtr); 743 } 744 break; 745 case FRAME_CONFIGURE: 746 if (objc <= 3) { 747 objPtr = Tk_GetOptionInfo(interp, (char *) framePtr, 748 framePtr->optionTable, 749 (objc == 3) ? objv[2] : NULL, 750 framePtr->tkwin); 751 if (objPtr == NULL) { 752 result = TCL_ERROR; 753 goto done; 754 } else { 755 Tcl_SetObjResult(interp, objPtr); 756 } 757 } else { 758 /* 759 * Don't allow the options -class, -colormap, -container, -screen, 760 * -use, or -visual to be changed. 761 */ 762 763 for (i = 2; i < objc; i++) { 764 char *arg = Tcl_GetStringFromObj(objv[i], &length); 765 if (length < 2) { 766 continue; 767 } 768 c = arg[1]; 769 if (((c == 'c') && (length >= 2) 770 && (strncmp(arg, "-class", (unsigned)length) == 0)) 771 || ((c == 'c') && (length >= 3) 772 && (strncmp(arg, "-colormap", (unsigned)length) == 0)) 773 || ((c == 'c') && (length >= 3) 774 && (strncmp(arg, "-container", (unsigned)length) == 0)) 775 || ((c == 's') && (framePtr->type == TYPE_TOPLEVEL) 776 && (strncmp(arg, "-screen", (unsigned)length) == 0)) 777 || ((c == 'u') && (framePtr->type == TYPE_TOPLEVEL) 778 && (strncmp(arg, "-use", (unsigned)length) == 0)) 779 || ((c == 'v') 780 && (strncmp(arg, "-visual", (unsigned)length) == 0))) { 781 782 #ifdef SUPPORT_CONFIG_EMBEDDED 783 if (c == 'u') { 784 CONST char *string = Tcl_GetString(objv[i+1]); 785 if (TkpUseWindow(interp, framePtr->tkwin, 786 string) != TCL_OK) { 787 result = TCL_ERROR; 788 goto done; 789 } 790 } else { 791 Tcl_AppendResult(interp, "can't modify ", arg, 792 " option after widget is created", NULL); 793 result = TCL_ERROR; 794 goto done; 795 } 796 #else 797 Tcl_AppendResult(interp, "can't modify ", arg, 798 " option after widget is created", NULL); 799 result = TCL_ERROR; 800 goto done; 801 #endif 802 } 803 } 804 result = ConfigureFrame(interp, framePtr, objc-2, objv+2); 805 } 806 break; 807 } 808 809 done: 810 Tcl_Release((ClientData) framePtr); 811 return result; 812} 813 814/* 815 *---------------------------------------------------------------------- 816 * 817 * DestroyFrame -- 818 * 819 * This function is invoked by Tcl_EventuallyFree or Tcl_Release to clean 820 * up the internal structure of a frame at a safe time (when no-one is 821 * using it anymore). 822 * 823 * Results: 824 * None. 825 * 826 * Side effects: 827 * Everything associated with the frame is freed up. 828 * 829 *---------------------------------------------------------------------- 830 */ 831 832static void 833DestroyFrame( 834 char *memPtr) /* Info about frame widget. */ 835{ 836 register Frame *framePtr = (Frame *) memPtr; 837 register Labelframe *labelframePtr = (Labelframe *) memPtr; 838 839 if (framePtr->type == TYPE_LABELFRAME) { 840 Tk_FreeTextLayout(labelframePtr->textLayout); 841 if (labelframePtr->textGC != None) { 842 Tk_FreeGC(framePtr->display, labelframePtr->textGC); 843 } 844 } 845 if (framePtr->colormap != None) { 846 Tk_FreeColormap(framePtr->display, framePtr->colormap); 847 } 848 ckfree((char *) framePtr); 849} 850 851/* 852 *---------------------------------------------------------------------- 853 * 854 * DestroyFramePartly -- 855 * 856 * This function is invoked to clean up everything that needs tkwin to be 857 * defined when deleted. During the destruction process tkwin is always 858 * set to NULL and this function must be called before that happens. 859 * 860 * Results: 861 * None. 862 * 863 * Side effects: 864 * Some things associated with the frame are freed up. 865 * 866 *---------------------------------------------------------------------- 867 */ 868 869static void 870DestroyFramePartly( 871 Frame *framePtr) /* Info about frame widget. */ 872{ 873 register Labelframe *labelframePtr = (Labelframe *) framePtr; 874 875 if (framePtr->type == TYPE_LABELFRAME && labelframePtr->labelWin != NULL) { 876 Tk_DeleteEventHandler(labelframePtr->labelWin, StructureNotifyMask, 877 FrameStructureProc, (ClientData) framePtr); 878 Tk_ManageGeometry(labelframePtr->labelWin, NULL, (ClientData) NULL); 879 if (framePtr->tkwin != Tk_Parent(labelframePtr->labelWin)) { 880 Tk_UnmaintainGeometry(labelframePtr->labelWin, framePtr->tkwin); 881 } 882 Tk_UnmapWindow(labelframePtr->labelWin); 883 labelframePtr->labelWin = NULL; 884 } 885 886 Tk_FreeConfigOptions((char *) framePtr, framePtr->optionTable, 887 framePtr->tkwin); 888} 889 890/* 891 *---------------------------------------------------------------------- 892 * 893 * ConfigureFrame -- 894 * 895 * This function is called to process an objv/objc list, plus the Tk 896 * option database, in order to configure (or reconfigure) a frame 897 * widget. 898 * 899 * Results: 900 * The return value is a standard Tcl result. If TCL_ERROR is returned, 901 * then the interp's result contains an error message. 902 * 903 * Side effects: 904 * Configuration information, such as text string, colors, font, etc. get 905 * set for framePtr; old resources get freed, if there were any. 906 * 907 *---------------------------------------------------------------------- 908 */ 909 910static int 911ConfigureFrame( 912 Tcl_Interp *interp, /* Used for error reporting. */ 913 register Frame *framePtr, /* Information about widget; may or may not 914 * already have values for some fields. */ 915 int objc, /* Number of valid entries in objv. */ 916 Tcl_Obj *CONST objv[]) /* Arguments. */ 917{ 918 Tk_SavedOptions savedOptions; 919 char *oldMenuName; 920 Tk_Window oldWindow = NULL; 921 Labelframe *labelframePtr = (Labelframe *) framePtr; 922 923 /* 924 * Need the old menubar name for the menu code to delete it. 925 */ 926 927 if (framePtr->menuName == NULL) { 928 oldMenuName = NULL; 929 } else { 930 oldMenuName = ckalloc(strlen(framePtr->menuName) + 1); 931 strcpy(oldMenuName, framePtr->menuName); 932 } 933 934 if (framePtr->type == TYPE_LABELFRAME) { 935 oldWindow = labelframePtr->labelWin; 936 } 937 if (Tk_SetOptions(interp, (char *) framePtr, 938 framePtr->optionTable, objc, objv, 939 framePtr->tkwin, &savedOptions, NULL) != TCL_OK) { 940 if (oldMenuName != NULL) { 941 ckfree(oldMenuName); 942 } 943 return TCL_ERROR; 944 } else { 945 Tk_FreeSavedOptions(&savedOptions); 946 } 947 948 /* 949 * A few of the options require additional processing. 950 */ 951 952 if ((((oldMenuName == NULL) && (framePtr->menuName != NULL)) 953 || ((oldMenuName != NULL) && (framePtr->menuName == NULL)) 954 || ((oldMenuName != NULL) && (framePtr->menuName != NULL) 955 && strcmp(oldMenuName, framePtr->menuName) != 0)) 956 && framePtr->type == TYPE_TOPLEVEL) { 957 TkSetWindowMenuBar(interp, framePtr->tkwin, oldMenuName, 958 framePtr->menuName); 959 } 960 961 if (oldMenuName != NULL) { 962 ckfree(oldMenuName); 963 } 964 965 if (framePtr->border != NULL) { 966 Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border); 967 } else { 968 Tk_SetWindowBackgroundPixmap(framePtr->tkwin, None); 969 } 970 971 if (framePtr->highlightWidth < 0) { 972 framePtr->highlightWidth = 0; 973 } 974 if (framePtr->padX < 0) { 975 framePtr->padX = 0; 976 } 977 if (framePtr->padY < 0) { 978 framePtr->padY = 0; 979 } 980 981 /* 982 * If a -labelwidget is specified, check that it is valid and set up 983 * geometry management for it. 984 */ 985 986 if (framePtr->type == TYPE_LABELFRAME) { 987 if (oldWindow != labelframePtr->labelWin) { 988 if (oldWindow != NULL) { 989 Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, 990 FrameStructureProc, (ClientData) framePtr); 991 Tk_ManageGeometry(oldWindow, NULL, (ClientData) NULL); 992 Tk_UnmaintainGeometry(oldWindow, framePtr->tkwin); 993 Tk_UnmapWindow(oldWindow); 994 } 995 if (labelframePtr->labelWin != NULL) { 996 Tk_Window ancestor, parent, sibling = NULL; 997 998 /* 999 * Make sure that the frame is either the parent of the window 1000 * used as label or a descendant of that parent. Also, don't 1001 * allow a top-level window to be managed inside the frame. 1002 */ 1003 1004 parent = Tk_Parent(labelframePtr->labelWin); 1005 for (ancestor = framePtr->tkwin; ; 1006 ancestor = Tk_Parent(ancestor)) { 1007 if (ancestor == parent) { 1008 break; 1009 } 1010 sibling = ancestor; 1011 if (Tk_IsTopLevel(ancestor)) { 1012 badWindow: 1013 Tcl_AppendResult(interp, "can't use ", 1014 Tk_PathName(labelframePtr->labelWin), 1015 " as label in this frame", NULL); 1016 labelframePtr->labelWin = NULL; 1017 return TCL_ERROR; 1018 } 1019 } 1020 if (Tk_IsTopLevel(labelframePtr->labelWin)) { 1021 goto badWindow; 1022 } 1023 if (labelframePtr->labelWin == framePtr->tkwin) { 1024 goto badWindow; 1025 } 1026 Tk_CreateEventHandler(labelframePtr->labelWin, 1027 StructureNotifyMask, FrameStructureProc, 1028 (ClientData) framePtr); 1029 Tk_ManageGeometry(labelframePtr->labelWin, &frameGeomType, 1030 (ClientData) framePtr); 1031 1032 /* 1033 * If the frame is not parent to the label, make sure the 1034 * label is above its sibling in the stacking order. 1035 */ 1036 1037 if (sibling != NULL) { 1038 Tk_RestackWindow(labelframePtr->labelWin, Above, sibling); 1039 } 1040 } 1041 } 1042 } 1043 1044 FrameWorldChanged((ClientData) framePtr); 1045 1046 return TCL_OK; 1047} 1048 1049/* 1050 *--------------------------------------------------------------------------- 1051 * 1052 * FrameWorldChanged -- 1053 * 1054 * This function is called when the world has changed in some way and the 1055 * widget needs to recompute all its graphics contexts and determine its 1056 * new geometry. 1057 * 1058 * Results: 1059 * None. 1060 * 1061 * Side effects: 1062 * Frame will be relayed out and redisplayed. 1063 * 1064 *--------------------------------------------------------------------------- 1065 */ 1066 1067static void 1068FrameWorldChanged( 1069 ClientData instanceData) /* Information about widget. */ 1070{ 1071 Frame *framePtr = (Frame *) instanceData; 1072 Labelframe *labelframePtr = (Labelframe *) framePtr; 1073 Tk_Window tkwin = framePtr->tkwin; 1074 XGCValues gcValues; 1075 GC gc; 1076 int anyTextLabel, anyWindowLabel; 1077 int bWidthLeft, bWidthRight, bWidthTop, bWidthBottom; 1078 char *labelText; 1079 1080 anyTextLabel = (framePtr->type == TYPE_LABELFRAME) && 1081 (labelframePtr->textPtr != NULL) && 1082 (labelframePtr->labelWin == NULL); 1083 anyWindowLabel = (framePtr->type == TYPE_LABELFRAME) && 1084 (labelframePtr->labelWin != NULL); 1085 1086 if (framePtr->type == TYPE_LABELFRAME) { 1087 /* 1088 * The textGC is needed even in the labelWin case, so it's always 1089 * created for a labelframe. 1090 */ 1091 1092 gcValues.font = Tk_FontId(labelframePtr->tkfont); 1093 gcValues.foreground = labelframePtr->textColorPtr->pixel; 1094 gcValues.graphics_exposures = False; 1095 gc = Tk_GetGC(tkwin, GCForeground | GCFont | GCGraphicsExposures, 1096 &gcValues); 1097 if (labelframePtr->textGC != None) { 1098 Tk_FreeGC(framePtr->display, labelframePtr->textGC); 1099 } 1100 labelframePtr->textGC = gc; 1101 1102 /* 1103 * Calculate label size. 1104 */ 1105 1106 labelframePtr->labelReqWidth = labelframePtr->labelReqHeight = 0; 1107 1108 if (anyTextLabel) { 1109 labelText = Tcl_GetString(labelframePtr->textPtr); 1110 Tk_FreeTextLayout(labelframePtr->textLayout); 1111 labelframePtr->textLayout = Tk_ComputeTextLayout(labelframePtr->tkfont, 1112 labelText, -1, 0, TK_JUSTIFY_CENTER, 0, 1113 &labelframePtr->labelReqWidth, &labelframePtr->labelReqHeight); 1114 labelframePtr->labelReqWidth += 2 * LABELSPACING; 1115 labelframePtr->labelReqHeight += 2 * LABELSPACING; 1116 } else if (anyWindowLabel) { 1117 labelframePtr->labelReqWidth = Tk_ReqWidth(labelframePtr->labelWin); 1118 labelframePtr->labelReqHeight = Tk_ReqHeight(labelframePtr->labelWin); 1119 } 1120 1121 /* 1122 * Make sure label size is at least as big as the border. This 1123 * simplifies later calculations and gives a better appearance with 1124 * thick borders. 1125 */ 1126 1127 if ((labelframePtr->labelAnchor >= LABELANCHOR_N) && 1128 (labelframePtr->labelAnchor <= LABELANCHOR_SW)) { 1129 if (labelframePtr->labelReqHeight < framePtr->borderWidth) { 1130 labelframePtr->labelReqHeight = framePtr->borderWidth; 1131 } 1132 } else { 1133 if (labelframePtr->labelReqWidth < framePtr->borderWidth) { 1134 labelframePtr->labelReqWidth = framePtr->borderWidth; 1135 } 1136 } 1137 } 1138 1139 /* 1140 * Calculate individual border widths. 1141 */ 1142 1143 bWidthBottom = bWidthTop = bWidthRight = bWidthLeft = 1144 framePtr->borderWidth + framePtr->highlightWidth; 1145 1146 bWidthLeft += framePtr->padX; 1147 bWidthRight += framePtr->padX; 1148 bWidthTop += framePtr->padY; 1149 bWidthBottom += framePtr->padY; 1150 1151 if (anyTextLabel || anyWindowLabel) { 1152 switch (labelframePtr->labelAnchor) { 1153 case LABELANCHOR_E: 1154 case LABELANCHOR_EN: 1155 case LABELANCHOR_ES: 1156 bWidthRight += labelframePtr->labelReqWidth - 1157 framePtr->borderWidth; 1158 break; 1159 case LABELANCHOR_N: 1160 case LABELANCHOR_NE: 1161 case LABELANCHOR_NW: 1162 bWidthTop += labelframePtr->labelReqHeight - framePtr->borderWidth; 1163 break; 1164 case LABELANCHOR_S: 1165 case LABELANCHOR_SE: 1166 case LABELANCHOR_SW: 1167 bWidthBottom += labelframePtr->labelReqHeight - 1168 framePtr->borderWidth; 1169 break; 1170 default: 1171 bWidthLeft += labelframePtr->labelReqWidth - framePtr->borderWidth; 1172 break; 1173 } 1174 } 1175 1176 Tk_SetInternalBorderEx(tkwin, bWidthLeft, bWidthRight, bWidthTop, 1177 bWidthBottom); 1178 1179 ComputeFrameGeometry(framePtr); 1180 1181 /* 1182 * A labelframe should request size for its label. 1183 */ 1184 1185 if (framePtr->type == TYPE_LABELFRAME) { 1186 int minwidth = labelframePtr->labelReqWidth; 1187 int minheight = labelframePtr->labelReqHeight; 1188 int padding = framePtr->highlightWidth; 1189 1190 if (framePtr->borderWidth > 0) { 1191 padding += framePtr->borderWidth + LABELMARGIN; 1192 } 1193 padding *= 2; 1194 if ((labelframePtr->labelAnchor >= LABELANCHOR_N) && 1195 (labelframePtr->labelAnchor <= LABELANCHOR_SW)) { 1196 minwidth += padding; 1197 minheight += framePtr->borderWidth + framePtr->highlightWidth; 1198 } else { 1199 minheight += padding; 1200 minwidth += framePtr->borderWidth + framePtr->highlightWidth; 1201 } 1202 Tk_SetMinimumRequestSize(tkwin, minwidth, minheight); 1203 } 1204 1205 if ((framePtr->width > 0) || (framePtr->height > 0)) { 1206 Tk_GeometryRequest(tkwin, framePtr->width, framePtr->height); 1207 } 1208 1209 if (Tk_IsMapped(tkwin)) { 1210 if (!(framePtr->flags & REDRAW_PENDING)) { 1211 Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr); 1212 } 1213 framePtr->flags |= REDRAW_PENDING; 1214 } 1215} 1216 1217/* 1218 *---------------------------------------------------------------------- 1219 * 1220 * ComputeFrameGeometry -- 1221 * 1222 * This function is called to compute various geometrical information for 1223 * a frame, such as where various things get displayed. It's called when 1224 * the window is reconfigured. 1225 * 1226 * Results: 1227 * None. 1228 * 1229 * Side effects: 1230 * Display-related numbers get changed in *framePtr. 1231 * 1232 *---------------------------------------------------------------------- 1233 */ 1234 1235static void 1236ComputeFrameGeometry( 1237 register Frame *framePtr) /* Information about widget. */ 1238{ 1239 int otherWidth, otherHeight, otherWidthT, otherHeightT, padding; 1240 int maxWidth, maxHeight; 1241 Tk_Window tkwin; 1242 Labelframe *labelframePtr = (Labelframe *) framePtr; 1243 1244 /* 1245 * We have nothing to do here unless there is a label. 1246 */ 1247 1248 if (framePtr->type != TYPE_LABELFRAME) return; 1249 if (labelframePtr->textPtr == NULL && labelframePtr->labelWin == NULL) { 1250 return; 1251 } 1252 1253 tkwin = framePtr->tkwin; 1254 1255 /* 1256 * Calculate the available size for the label 1257 */ 1258 1259 labelframePtr->labelBox.width = labelframePtr->labelReqWidth; 1260 labelframePtr->labelBox.height = labelframePtr->labelReqHeight; 1261 1262 padding = framePtr->highlightWidth; 1263 if (framePtr->borderWidth > 0) { 1264 padding += framePtr->borderWidth + LABELMARGIN; 1265 } 1266 padding *= 2; 1267 1268 maxHeight = Tk_Height(tkwin); 1269 maxWidth = Tk_Width(tkwin); 1270 1271 if ((labelframePtr->labelAnchor >= LABELANCHOR_N) && 1272 (labelframePtr->labelAnchor <= LABELANCHOR_SW)) { 1273 maxWidth -= padding; 1274 if (maxWidth < 1) maxWidth = 1; 1275 } else { 1276 maxHeight -= padding; 1277 if (maxHeight < 1) maxHeight = 1; 1278 } 1279 if (labelframePtr->labelBox.width > maxWidth) { 1280 labelframePtr->labelBox.width = maxWidth; 1281 } 1282 if (labelframePtr->labelBox.height > maxHeight) { 1283 labelframePtr->labelBox.height = maxHeight; 1284 } 1285 1286 /* 1287 * Calculate label and text position. The text's position is based on the 1288 * requested size (= the text's real size) to get proper alignment if the 1289 * text does not fit. 1290 */ 1291 1292 otherWidth = Tk_Width(tkwin) - labelframePtr->labelBox.width; 1293 otherHeight = Tk_Height(tkwin) - labelframePtr->labelBox.height; 1294 otherWidthT = Tk_Width(tkwin) - labelframePtr->labelReqWidth; 1295 otherHeightT = Tk_Height(tkwin) - labelframePtr->labelReqHeight; 1296 padding = framePtr->highlightWidth; 1297 1298 switch (labelframePtr->labelAnchor) { 1299 case LABELANCHOR_E: 1300 case LABELANCHOR_EN: 1301 case LABELANCHOR_ES: 1302 labelframePtr->labelTextX = otherWidthT - padding; 1303 labelframePtr->labelBox.x = otherWidth - padding; 1304 break; 1305 case LABELANCHOR_N: 1306 case LABELANCHOR_NE: 1307 case LABELANCHOR_NW: 1308 labelframePtr->labelTextY = padding; 1309 labelframePtr->labelBox.y = padding; 1310 break; 1311 case LABELANCHOR_S: 1312 case LABELANCHOR_SE: 1313 case LABELANCHOR_SW: 1314 labelframePtr->labelTextY = otherHeightT - padding; 1315 labelframePtr->labelBox.y = otherHeight - padding; 1316 break; 1317 default: 1318 labelframePtr->labelTextX = padding; 1319 labelframePtr->labelBox.x = padding; 1320 break; 1321 } 1322 1323 if (framePtr->borderWidth > 0) { 1324 padding += framePtr->borderWidth + LABELMARGIN; 1325 } 1326 1327 switch (labelframePtr->labelAnchor) { 1328 case LABELANCHOR_NW: 1329 case LABELANCHOR_SW: 1330 labelframePtr->labelTextX = padding; 1331 labelframePtr->labelBox.x = padding; 1332 break; 1333 case LABELANCHOR_N: 1334 case LABELANCHOR_S: 1335 labelframePtr->labelTextX = otherWidthT / 2; 1336 labelframePtr->labelBox.x = otherWidth / 2; 1337 break; 1338 case LABELANCHOR_NE: 1339 case LABELANCHOR_SE: 1340 labelframePtr->labelTextX = otherWidthT - padding; 1341 labelframePtr->labelBox.x = otherWidth - padding; 1342 break; 1343 case LABELANCHOR_EN: 1344 case LABELANCHOR_WN: 1345 labelframePtr->labelTextY = padding; 1346 labelframePtr->labelBox.y = padding; 1347 break; 1348 case LABELANCHOR_E: 1349 case LABELANCHOR_W: 1350 labelframePtr->labelTextY = otherHeightT / 2; 1351 labelframePtr->labelBox.y = otherHeight / 2; 1352 break; 1353 default: 1354 labelframePtr->labelTextY = otherHeightT - padding; 1355 labelframePtr->labelBox.y = otherHeight - padding; 1356 break; 1357 } 1358} 1359 1360/* 1361 *---------------------------------------------------------------------- 1362 * 1363 * DisplayFrame -- 1364 * 1365 * This function is invoked to display a frame widget. 1366 * 1367 * Results: 1368 * None. 1369 * 1370 * Side effects: 1371 * Commands are output to X to display the frame in its current mode. 1372 * 1373 *---------------------------------------------------------------------- 1374 */ 1375 1376static void 1377DisplayFrame( 1378 ClientData clientData) /* Information about widget. */ 1379{ 1380 register Frame *framePtr = (Frame *) clientData; 1381 register Tk_Window tkwin = framePtr->tkwin; 1382 int bdX1, bdY1, bdX2, bdY2, hlWidth; 1383 Pixmap pixmap; 1384 TkRegion clipRegion = NULL; 1385 1386 framePtr->flags &= ~REDRAW_PENDING; 1387 if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { 1388 return; 1389 } 1390 1391 /* 1392 * Highlight shall always be drawn if it exists, so do that first. 1393 */ 1394 1395 hlWidth = framePtr->highlightWidth; 1396 1397 if (hlWidth != 0) { 1398 GC fgGC, bgGC; 1399 1400 bgGC = Tk_GCForColor(framePtr->highlightBgColorPtr, 1401 Tk_WindowId(tkwin)); 1402 if (framePtr->flags & GOT_FOCUS) { 1403 fgGC = Tk_GCForColor(framePtr->highlightColorPtr, 1404 Tk_WindowId(tkwin)); 1405 TkpDrawHighlightBorder(tkwin, fgGC, bgGC, hlWidth, 1406 Tk_WindowId(tkwin)); 1407 } else { 1408 TkpDrawHighlightBorder(tkwin, bgGC, bgGC, hlWidth, 1409 Tk_WindowId(tkwin)); 1410 } 1411 } 1412 1413 /* 1414 * If -background is set to "", no interior is drawn. 1415 */ 1416 1417 if (framePtr->border == NULL) return; 1418 1419 if (framePtr->type != TYPE_LABELFRAME) { 1420 /* 1421 * Pass to platform specific draw function. In general, it just draws 1422 * a simple rectangle, but it may "theme" the background. 1423 */ 1424 1425 noLabel: 1426 TkpDrawFrame(tkwin, framePtr->border, hlWidth, 1427 framePtr->borderWidth, framePtr->relief); 1428 } else { 1429 Labelframe *labelframePtr = (Labelframe *) framePtr; 1430 1431 if ((labelframePtr->textPtr == NULL) && 1432 (labelframePtr->labelWin == NULL)) { 1433 goto noLabel; 1434 } 1435 1436#ifndef TK_NO_DOUBLE_BUFFERING 1437 /* 1438 * In order to avoid screen flashes, this function redraws the frame 1439 * into off-screen memory, then copies it back on-screen in a single 1440 * operation. This means there's no point in time where the on-screen 1441 * image has been cleared. 1442 */ 1443 1444 pixmap = Tk_GetPixmap(framePtr->display, Tk_WindowId(tkwin), 1445 Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); 1446#else 1447 pixmap = Tk_WindowId(tkwin); 1448#endif /* TK_NO_DOUBLE_BUFFERING */ 1449 1450 /* 1451 * Clear the pixmap. 1452 */ 1453 1454 Tk_Fill3DRectangle(tkwin, pixmap, framePtr->border, 0, 0, 1455 Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); 1456 1457 /* 1458 * Calculate how the label affects the border's position. 1459 */ 1460 1461 bdX1 = bdY1 = hlWidth; 1462 bdX2 = Tk_Width(tkwin) - hlWidth; 1463 bdY2 = Tk_Height(tkwin) - hlWidth; 1464 1465 switch (labelframePtr->labelAnchor) { 1466 case LABELANCHOR_E: 1467 case LABELANCHOR_EN: 1468 case LABELANCHOR_ES: 1469 bdX2 -= (labelframePtr->labelBox.width-framePtr->borderWidth) / 2; 1470 break; 1471 case LABELANCHOR_N: 1472 case LABELANCHOR_NE: 1473 case LABELANCHOR_NW: 1474 /* 1475 * Since the glyphs of the text tend to be in the lower part we 1476 * favor a lower border position by rounding up. 1477 */ 1478 1479 bdY1 += (labelframePtr->labelBox.height-framePtr->borderWidth+1)/2; 1480 break; 1481 case LABELANCHOR_S: 1482 case LABELANCHOR_SE: 1483 case LABELANCHOR_SW: 1484 bdY2 -= (labelframePtr->labelBox.height-framePtr->borderWidth) / 2; 1485 break; 1486 default: 1487 bdX1 += (labelframePtr->labelBox.width-framePtr->borderWidth) / 2; 1488 break; 1489 } 1490 1491 /* 1492 * Draw border 1493 */ 1494 1495 Tk_Draw3DRectangle(tkwin, pixmap, framePtr->border, bdX1, bdY1, 1496 bdX2 - bdX1, bdY2 - bdY1, framePtr->borderWidth, 1497 framePtr->relief); 1498 1499 if (labelframePtr->labelWin == NULL) { 1500 /* 1501 * Clear behind the label 1502 */ 1503 1504 Tk_Fill3DRectangle(tkwin, pixmap, 1505 framePtr->border, labelframePtr->labelBox.x, 1506 labelframePtr->labelBox.y, labelframePtr->labelBox.width, 1507 labelframePtr->labelBox.height, 0, TK_RELIEF_FLAT); 1508 1509 /* 1510 * Draw label. If there is not room for the entire label, use 1511 * clipping to get a nice appearance. 1512 */ 1513 1514 if ((labelframePtr->labelBox.width < labelframePtr->labelReqWidth) 1515 || (labelframePtr->labelBox.height < 1516 labelframePtr->labelReqHeight)) { 1517 clipRegion = TkCreateRegion(); 1518 TkUnionRectWithRegion(&labelframePtr->labelBox, clipRegion, 1519 clipRegion); 1520 TkSetRegion(framePtr->display, labelframePtr->textGC, 1521 clipRegion); 1522 } 1523 1524 Tk_DrawTextLayout(framePtr->display, pixmap, 1525 labelframePtr->textGC, labelframePtr->textLayout, 1526 labelframePtr->labelTextX + LABELSPACING, 1527 labelframePtr->labelTextY + LABELSPACING, 0, -1); 1528 1529 if (clipRegion != NULL) { 1530 XSetClipMask(framePtr->display, labelframePtr->textGC, None); 1531 TkDestroyRegion(clipRegion); 1532 } 1533 } else { 1534 /* 1535 * Reposition and map the window (but in different ways depending 1536 * on whether the frame is the window's parent). 1537 */ 1538 1539 if (framePtr->tkwin == Tk_Parent(labelframePtr->labelWin)) { 1540 if ((labelframePtr->labelBox.x != Tk_X(labelframePtr->labelWin)) 1541 || (labelframePtr->labelBox.y != 1542 Tk_Y(labelframePtr->labelWin)) 1543 || (labelframePtr->labelBox.width != 1544 Tk_Width(labelframePtr->labelWin)) 1545 || (labelframePtr->labelBox.height != 1546 Tk_Height(labelframePtr->labelWin))) { 1547 Tk_MoveResizeWindow(labelframePtr->labelWin, 1548 labelframePtr->labelBox.x, labelframePtr->labelBox.y, 1549 labelframePtr->labelBox.width, 1550 labelframePtr->labelBox.height); 1551 } 1552 Tk_MapWindow(labelframePtr->labelWin); 1553 } else { 1554 Tk_MaintainGeometry(labelframePtr->labelWin, framePtr->tkwin, 1555 labelframePtr->labelBox.x, labelframePtr->labelBox.y, 1556 labelframePtr->labelBox.width, 1557 labelframePtr->labelBox.height); 1558 } 1559 } 1560 1561 1562#ifndef TK_NO_DOUBLE_BUFFERING 1563 /* 1564 * Everything's been redisplayed; now copy the pixmap onto the screen 1565 * and free up the pixmap. 1566 */ 1567 1568 XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin), 1569 labelframePtr->textGC, hlWidth, hlWidth, 1570 (unsigned) (Tk_Width(tkwin) - 2 * hlWidth), 1571 (unsigned) (Tk_Height(tkwin) - 2 * hlWidth), 1572 hlWidth, hlWidth); 1573 Tk_FreePixmap(framePtr->display, pixmap); 1574#endif /* TK_NO_DOUBLE_BUFFERING */ 1575 } 1576 1577} 1578 1579/* 1580 *-------------------------------------------------------------- 1581 * 1582 * FrameEventProc -- 1583 * 1584 * This function is invoked by the Tk dispatcher on structure changes to 1585 * a frame. For frames with 3D borders, this function is also invoked for 1586 * exposures. 1587 * 1588 * Results: 1589 * None. 1590 * 1591 * Side effects: 1592 * When the window gets deleted, internal structures get cleaned up. 1593 * When it gets exposed, it is redisplayed. 1594 * 1595 *-------------------------------------------------------------- 1596 */ 1597 1598static void 1599FrameEventProc( 1600 ClientData clientData, /* Information about window. */ 1601 register XEvent *eventPtr) /* Information about event. */ 1602{ 1603 register Frame *framePtr = (Frame *) clientData; 1604 1605 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { 1606 goto redraw; 1607 } else if (eventPtr->type == ConfigureNotify) { 1608 ComputeFrameGeometry(framePtr); 1609 goto redraw; 1610 } else if (eventPtr->type == DestroyNotify) { 1611 if (framePtr->menuName != NULL) { 1612 TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, 1613 framePtr->menuName, NULL); 1614 ckfree(framePtr->menuName); 1615 framePtr->menuName = NULL; 1616 } 1617 if (framePtr->tkwin != NULL) { 1618 /* 1619 * If this window is a container, then this event could be coming 1620 * from the embedded application, in which case Tk_DestroyWindow 1621 * hasn't been called yet. When Tk_DestroyWindow is called later, 1622 * then another destroy event will be generated. We need to be 1623 * sure we ignore the second event, since the frame could be gone 1624 * by then. To do so, delete the event handler explicitly 1625 * (normally it's done implicitly by Tk_DestroyWindow). 1626 */ 1627 1628 /* 1629 * Since the tkwin pointer will be gone when we reach 1630 * DestroyFrame, we must free all options now. 1631 */ 1632 1633 DestroyFramePartly(framePtr); 1634 1635 Tk_DeleteEventHandler(framePtr->tkwin, 1636 ExposureMask|StructureNotifyMask|FocusChangeMask, 1637 FrameEventProc, (ClientData) framePtr); 1638 framePtr->tkwin = NULL; 1639 Tcl_DeleteCommandFromToken(framePtr->interp, framePtr->widgetCmd); 1640 } 1641 if (framePtr->flags & REDRAW_PENDING) { 1642 Tcl_CancelIdleCall(DisplayFrame, (ClientData) framePtr); 1643 } 1644 Tcl_CancelIdleCall(MapFrame, (ClientData) framePtr); 1645 Tcl_EventuallyFree((ClientData) framePtr, DestroyFrame); 1646 } else if (eventPtr->type == FocusIn) { 1647 if (eventPtr->xfocus.detail != NotifyInferior) { 1648 framePtr->flags |= GOT_FOCUS; 1649 if (framePtr->highlightWidth > 0) { 1650 goto redraw; 1651 } 1652 } 1653 } else if (eventPtr->type == FocusOut) { 1654 if (eventPtr->xfocus.detail != NotifyInferior) { 1655 framePtr->flags &= ~GOT_FOCUS; 1656 if (framePtr->highlightWidth > 0) { 1657 goto redraw; 1658 } 1659 } 1660 } else if (eventPtr->type == ActivateNotify) { 1661 TkpSetMainMenubar(framePtr->interp, framePtr->tkwin, 1662 framePtr->menuName); 1663 } 1664 return; 1665 1666 redraw: 1667 if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) { 1668 Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr); 1669 framePtr->flags |= REDRAW_PENDING; 1670 } 1671} 1672 1673/* 1674 *---------------------------------------------------------------------- 1675 * 1676 * FrameCmdDeletedProc -- 1677 * 1678 * This function is invoked when a widget command is deleted. If the 1679 * widget isn't already in the process of being destroyed, this command 1680 * destroys it. 1681 * 1682 * Results: 1683 * None. 1684 * 1685 * Side effects: 1686 * The widget is destroyed. 1687 * 1688 *---------------------------------------------------------------------- 1689 */ 1690 1691static void 1692FrameCmdDeletedProc( 1693 ClientData clientData) /* Pointer to widget record for widget. */ 1694{ 1695 Frame *framePtr = (Frame *) clientData; 1696 Tk_Window tkwin = framePtr->tkwin; 1697 1698 if (framePtr->menuName != NULL) { 1699 TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, 1700 framePtr->menuName, NULL); 1701 ckfree(framePtr->menuName); 1702 framePtr->menuName = NULL; 1703 } 1704 1705 /* 1706 * This function could be invoked either because the window was destroyed 1707 * and the command was then deleted (in which case tkwin is NULL) or 1708 * because the command was deleted, and then this function destroys the 1709 * widget. 1710 */ 1711 1712 if (tkwin != NULL) { 1713 /* 1714 * Some options need tkwin to be freed, so we free them here, before 1715 * setting tkwin to NULL. 1716 */ 1717 1718 DestroyFramePartly(framePtr); 1719 1720 framePtr->tkwin = NULL; 1721 Tk_DestroyWindow(tkwin); 1722 } 1723} 1724 1725/* 1726 *---------------------------------------------------------------------- 1727 * 1728 * MapFrame -- 1729 * 1730 * This function is invoked as a when-idle handler to map a newly-created 1731 * top-level frame. 1732 * 1733 * Results: 1734 * None. 1735 * 1736 * Side effects: 1737 * The frame given by the clientData argument is mapped. 1738 * 1739 *---------------------------------------------------------------------- 1740 */ 1741 1742static void 1743MapFrame( 1744 ClientData clientData) /* Pointer to frame structure. */ 1745{ 1746 Frame *framePtr = (Frame *) clientData; 1747 1748 /* 1749 * Wait for all other background events to be processed before mapping 1750 * window. This ensures that the window's correct geometry will have been 1751 * determined before it is first mapped, so that the window manager 1752 * doesn't get a false idea of its desired geometry. 1753 */ 1754 1755 Tcl_Preserve((ClientData) framePtr); 1756 while (1) { 1757 if (Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) { 1758 break; 1759 } 1760 1761 /* 1762 * After each event, make sure that the window still exists and quit 1763 * if the window has been destroyed. 1764 */ 1765 1766 if (framePtr->tkwin == NULL) { 1767 Tcl_Release((ClientData) framePtr); 1768 return; 1769 } 1770 } 1771 Tk_MapWindow(framePtr->tkwin); 1772 Tcl_Release((ClientData) framePtr); 1773} 1774 1775/* 1776 *-------------------------------------------------------------- 1777 * 1778 * TkInstallFrameMenu -- 1779 * 1780 * This function is needed when a Windows HWND is created and a menubar 1781 * has been set to the window with a system menu. It notifies the menu 1782 * package so that the system menu can be rebuilt. 1783 * 1784 * Results: 1785 * None. 1786 * 1787 * Side effects: 1788 * The system menu (if any) is created for the menubar associated with 1789 * this frame. 1790 * 1791 *-------------------------------------------------------------- 1792 */ 1793 1794void 1795TkInstallFrameMenu( 1796 Tk_Window tkwin) /* The window that was just created. */ 1797{ 1798 TkWindow *winPtr = (TkWindow *) tkwin; 1799 1800 if (winPtr->mainPtr != NULL) { 1801 Frame *framePtr; 1802 framePtr = (Frame*) winPtr->instanceData; 1803 if (framePtr == NULL) { 1804 Tcl_Panic("TkInstallFrameMenu couldn't get frame pointer"); 1805 } 1806 TkpMenuNotifyToplevelCreate(winPtr->mainPtr->interp, 1807 framePtr->menuName); 1808 } 1809} 1810 1811/* 1812 *-------------------------------------------------------------- 1813 * 1814 * FrameStructureProc -- 1815 * 1816 * This function is invoked whenever StructureNotify events occur for a 1817 * window that's managed as label for the frame. This procudure's only 1818 * purpose is to clean up when windows are deleted. 1819 * 1820 * Results: 1821 * None. 1822 * 1823 * Side effects: 1824 * The window is disassociated from the frame when it is deleted. 1825 * 1826 *-------------------------------------------------------------- 1827 */ 1828 1829static void 1830FrameStructureProc( 1831 ClientData clientData, /* Pointer to record describing frame. */ 1832 XEvent *eventPtr) /* Describes what just happened. */ 1833{ 1834 Labelframe *labelframePtr = (Labelframe *) clientData; 1835 1836 if (eventPtr->type == DestroyNotify) { 1837 /* 1838 * This should only happen in a labelframe but it doesn't hurt to be 1839 * careful. 1840 */ 1841 1842 if (labelframePtr->frame.type == TYPE_LABELFRAME) { 1843 labelframePtr->labelWin = NULL; 1844 FrameWorldChanged((ClientData) labelframePtr); 1845 } 1846 } 1847} 1848 1849/* 1850 *-------------------------------------------------------------- 1851 * 1852 * FrameRequestProc -- 1853 * 1854 * This function is invoked whenever a window that's associated with a 1855 * frame changes its requested dimensions. 1856 * 1857 * Results: 1858 * None. 1859 * 1860 * Side effects: 1861 * The size and location on the screen of the window may change depending 1862 * on the options specified for the frame. 1863 * 1864 *-------------------------------------------------------------- 1865 */ 1866 1867static void 1868FrameRequestProc( 1869 ClientData clientData, /* Pointer to record for frame. */ 1870 Tk_Window tkwin) /* Window that changed its desired size. */ 1871{ 1872 Frame *framePtr = (Frame *) clientData; 1873 1874 FrameWorldChanged((ClientData) framePtr); 1875} 1876 1877/* 1878 *-------------------------------------------------------------- 1879 * 1880 * FrameLostSlaveProc -- 1881 * 1882 * This function is invoked by Tk whenever some other geometry claims 1883 * control over a slave that used to be managed by us. 1884 * 1885 * Results: 1886 * None. 1887 * 1888 * Side effects: 1889 * Forgets all frame-related information about the slave. 1890 * 1891 *-------------------------------------------------------------- 1892 */ 1893 1894static void 1895FrameLostSlaveProc( 1896 ClientData clientData, /* Frame structure for slave window that was 1897 * stolen away. */ 1898 Tk_Window tkwin) /* Tk's handle for the slave window. */ 1899{ 1900 Frame *framePtr = (Frame *) clientData; 1901 Labelframe *labelframePtr = (Labelframe *) clientData; 1902 1903 /* 1904 * This should only happen in a labelframe but it doesn't hurt to be 1905 * careful. 1906 */ 1907 1908 if (labelframePtr->frame.type == TYPE_LABELFRAME) { 1909 Tk_DeleteEventHandler(labelframePtr->labelWin, StructureNotifyMask, 1910 FrameStructureProc, (ClientData) labelframePtr); 1911 if (framePtr->tkwin != Tk_Parent(labelframePtr->labelWin)) { 1912 Tk_UnmaintainGeometry(labelframePtr->labelWin, framePtr->tkwin); 1913 } 1914 Tk_UnmapWindow(labelframePtr->labelWin); 1915 labelframePtr->labelWin = NULL; 1916 } 1917 FrameWorldChanged((ClientData) framePtr); 1918} 1919 1920void 1921TkMapTopFrame (tkwin) 1922 Tk_Window tkwin; 1923{ 1924 Frame *framePtr = ((TkWindow*)tkwin)->instanceData; 1925 Tk_OptionTable optionTable; 1926 if (Tk_IsTopLevel(tkwin) && framePtr->type == TYPE_FRAME) { 1927 framePtr->type = TYPE_TOPLEVEL; 1928 Tcl_DoWhenIdle(MapFrame, (ClientData)framePtr); 1929 if (framePtr->menuName != NULL) { 1930 TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, NULL, 1931 framePtr->menuName); 1932 } 1933 } else if (!Tk_IsTopLevel(tkwin) && framePtr->type == TYPE_TOPLEVEL) { 1934 framePtr->type = TYPE_FRAME; 1935 } else { 1936 /* Not a frame or toplevel, skip it */ 1937 return; 1938 } 1939 /* 1940 * The option table has already been created so 1941 * the cached pointer will be returned. 1942 */ 1943 optionTable = Tk_CreateOptionTable(framePtr->interp, optionSpecs[framePtr->type]); 1944 framePtr->optionTable = optionTable; 1945} 1946 1947/* 1948 *-------------------------------------------------------------- 1949 * 1950 * TkToplevelWindowFromCommandToken -- 1951 * 1952 * If the given command name to the command for a toplevel window in the 1953 * given interpreter, return the tkwin for that toplevel window. Note 1954 * that this lookup can't be done using the standard tkwin internal table 1955 * because the command might have been renamed. 1956 * 1957 * Results: 1958 * A Tk_Window token, or NULL if the name does not refer to a toplevel 1959 * window. 1960 * 1961 * Side effects: 1962 * None. 1963 * 1964 *-------------------------------------------------------------- 1965 */ 1966 1967Tk_Window 1968TkToplevelWindowForCommand( 1969 Tcl_Interp *interp, 1970 CONST char *cmdName) 1971{ 1972 Tcl_CmdInfo cmdInfo; 1973 Frame *framePtr; 1974 1975 if (Tcl_GetCommandInfo(interp, cmdName, &cmdInfo) == 0) { 1976 return NULL; 1977 } 1978 if (cmdInfo.objProc != FrameWidgetObjCmd) { 1979 return NULL; 1980 } 1981 framePtr = (Frame *) cmdInfo.objClientData; 1982 if (framePtr->type != TYPE_TOPLEVEL) { 1983 return NULL; 1984 } 1985 return framePtr->tkwin; 1986} 1987 1988/* 1989 * Local Variables: 1990 * mode: c 1991 * c-basic-offset: 4 1992 * fill-column: 78 1993 * End: 1994 */ 1995