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