4 * This module implements "frame" and "toplevel" widgets for the
5 * toolkit. Frames are windows with a background color
6 * and possibly border, but no other attributes.
8 * Copyright (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10 * Copyright (c) 1995 Christian Werner
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * A data structure of the following type is kept for each
22 * frame that currently exists for this process:
26 CkWindow *winPtr; /* Window that embodies the frame. NULL
27 * means that the window has been destroyed
28 * but the data structures haven't yet been
30 Tcl_Interp *interp; /* Interpreter associated with widget.
31 * Used to delete widget command. */
32 Tcl_Command widgetCmd; /* Token for frame's widget command. */
33 CkBorder *borderPtr; /* Structure used to draw border. */
34 int fg, bg; /* Foreground/background colors. */
35 int attr; /* Video attributes. */
36 int width; /* Width to request for window. <= 0 means
37 * don't request any size. */
38 int height; /* Height to request for window. <= 0 means
39 * don't request any size. */
40 char *takeFocus; /* Value of -takefocus option. */
41 int flags; /* Various flags; see below for
46 * Flag bits for frames:
48 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
49 * has already been queued to redraw
53 #define REDRAW_PENDING 1
55 static Ck_ConfigSpec configSpecs[] = {
56 {CK_CONFIG_ATTR, "-attributes", "attributes", "Attributes",
57 DEF_FRAME_ATTRIB, Ck_Offset(Frame, attr), 0},
58 {CK_CONFIG_COLOR, "-background", "background", "Background",
59 DEF_FRAME_BG_COLOR, Ck_Offset(Frame, bg), CK_CONFIG_COLOR_ONLY},
60 {CK_CONFIG_COLOR, "-background", "background", "Background",
61 DEF_FRAME_BG_MONO, Ck_Offset(Frame, bg), CK_CONFIG_MONO_ONLY},
62 {CK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
64 {CK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
65 DEF_FRAME_FG_COLOR, Ck_Offset(Frame, fg), CK_CONFIG_COLOR_ONLY},
66 {CK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
67 DEF_FRAME_FG_MONO, Ck_Offset(Frame, fg), CK_CONFIG_MONO_ONLY},
68 {CK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
70 {CK_CONFIG_BORDER, "-border", "border", "Border",
71 DEF_FRAME_BORDER, Ck_Offset(Frame, borderPtr), CK_CONFIG_NULL_OK},
72 {CK_CONFIG_COORD, "-height", "height", "Height",
73 DEF_FRAME_HEIGHT, Ck_Offset(Frame, height), 0},
74 {CK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
75 DEF_FRAME_TAKE_FOCUS, Ck_Offset(Frame, takeFocus),
77 {CK_CONFIG_COORD, "-width", "width", "Width",
78 DEF_FRAME_WIDTH, Ck_Offset(Frame, width), 0},
79 {CK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
84 * Forward declarations for procedures defined later in this file:
87 static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp,
88 Frame *framePtr, int argc, char **argv, int flags));
89 static void DestroyFrame _ANSI_ARGS_((ClientData clientData));
90 static void FrameCmdDeletedProc _ANSI_ARGS_((ClientData clientData));
91 static void DisplayFrame _ANSI_ARGS_((ClientData clientData));
92 static void FrameEventProc _ANSI_ARGS_((ClientData clientData,
94 static int FrameWidgetCmd _ANSI_ARGS_((ClientData clientData,
95 Tcl_Interp *interp, int argc, char **argv));
98 *--------------------------------------------------------------
102 * This procedure is invoked to process the "frame" and
103 * "toplevel" Tcl commands. See the user documentation for
104 * details on what it does.
107 * A standard Tcl result.
110 * See the user documentation.
112 *--------------------------------------------------------------
116 Ck_FrameCmd(clientData, interp, argc, argv)
117 ClientData clientData; /* Main window associated with
119 Tcl_Interp *interp; /* Current interpreter. */
120 int argc; /* Number of arguments. */
121 char **argv; /* Argument strings. */
123 CkWindow *winPtr = (CkWindow *) clientData;
126 int src, dst, toplevel;
129 Tcl_AppendResult(interp, "wrong # args: should be \"",
130 argv[0], " pathName ?options?\"", (char *) NULL);
135 * The code below is a special hack that extracts a few key
136 * options from the argument list now, rather than letting
137 * ConfigureFrame do it. This is necessary because we have
138 * to know the window's class before creating the window.
141 toplevel = *argv[0] == 't';
143 for (src = 2, dst = 2; src < argc; src += 2) {
148 && (strncmp(argv[src], "-class", strlen(argv[src])) == 0)) {
149 className = argv[src+1];
151 argv[dst] = argv[src];
152 argv[dst+1] = argv[src+1];
159 * Create the window and initialize our structures and event handlers.
162 new = Ck_CreateWindowFromPath(interp, winPtr, argv[1], toplevel);
165 if (className == NULL) {
166 className = Ck_GetOption(new, "class", "Class");
167 if (className == NULL) {
168 className = (toplevel) ? "Toplevel" : "Frame";
171 Ck_SetClass(new, className);
172 return CkInitFrame(interp, new, argc-2, argv+2);
176 *----------------------------------------------------------------------
180 * This procedure initializes a frame widget. It's
181 * separate from Ck_FrameCmd so that it can be used for the
182 * main window, which has already been created elsewhere.
185 * A standard Tcl completion code.
188 * A widget record gets allocated, handlers get set up, etc..
190 *----------------------------------------------------------------------
194 CkInitFrame(interp, winPtr, argc, argv)
195 Tcl_Interp *interp; /* Interpreter associated with the
197 CkWindow *winPtr; /* Window to use for frame or
198 * top-level. Caller must already
199 * have set window's class. */
200 int argc; /* Number of configuration arguments
201 * (not including class command and
203 char *argv[]; /* Configuration arguments. */
207 framePtr = (Frame *) ckalloc(sizeof (Frame));
208 framePtr->winPtr = winPtr;
209 framePtr->interp = interp;
210 framePtr->widgetCmd = Tcl_CreateCommand(interp,
211 framePtr->winPtr->pathName, FrameWidgetCmd,
212 (ClientData) framePtr, FrameCmdDeletedProc);
213 framePtr->borderPtr = NULL;
218 framePtr->height = 1;
219 framePtr->takeFocus = NULL;
221 Ck_CreateEventHandler(framePtr->winPtr,
222 CK_EV_MAP | CK_EV_EXPOSE | CK_EV_DESTROY,
223 FrameEventProc, (ClientData) framePtr);
224 if (ConfigureFrame(interp, framePtr, argc, argv, 0) != TCL_OK) {
225 Ck_DestroyWindow(framePtr->winPtr);
228 interp->result = framePtr->winPtr->pathName;
233 *--------------------------------------------------------------
237 * This procedure is invoked to process the Tcl command
238 * that corresponds to a frame widget. See the user
239 * documentation for details on what it does.
242 * A standard Tcl result.
245 * See the user documentation.
247 *--------------------------------------------------------------
251 FrameWidgetCmd(clientData, interp, argc, argv)
252 ClientData clientData; /* Information about frame widget. */
253 Tcl_Interp *interp; /* Current interpreter. */
254 int argc; /* Number of arguments. */
255 char **argv; /* Argument strings. */
257 Frame *framePtr = (Frame *) clientData;
263 Tcl_AppendResult(interp, "wrong # args: should be \"",
264 argv[0], " option ?arg arg ...?\"", (char *) NULL);
267 Ck_Preserve((ClientData) framePtr);
269 length = strlen(argv[1]);
270 if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
273 Tcl_AppendResult(interp, "wrong # args: should be \"",
274 argv[0], " cget option\"",
278 result = Ck_ConfigureValue(interp, framePtr->winPtr, configSpecs,
279 (char *) framePtr, argv[2], 0);
280 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
282 result = Ck_ConfigureInfo(interp, framePtr->winPtr, configSpecs,
283 (char *) framePtr, (char *) NULL, 0);
284 } else if (argc == 3) {
285 result = Ck_ConfigureInfo(interp, framePtr->winPtr, configSpecs,
286 (char *) framePtr, argv[2], 0);
288 result = ConfigureFrame(interp, framePtr, argc-2, argv+2,
289 CK_CONFIG_ARGV_ONLY);
292 Tcl_AppendResult(interp, "bad option \"", argv[1],
293 "\": must be cget or configure", (char *) NULL);
296 Ck_Release((ClientData) framePtr);
300 Ck_Release((ClientData) framePtr);
305 *----------------------------------------------------------------------
309 * This procedure is invoked by Ck_EventuallyFree or Ck_Release
310 * to clean up the internal structure of a frame at a safe time
311 * (when no-one is using it anymore).
317 * Everything associated with the frame is freed up.
319 *----------------------------------------------------------------------
323 DestroyFrame(clientData)
324 ClientData clientData; /* Info about frame widget. */
326 Frame *framePtr = (Frame *) clientData;
328 Ck_FreeOptions(configSpecs, (char *) framePtr, 0);
329 ckfree((char *) framePtr);
333 *----------------------------------------------------------------------
335 * FrameCmdDeletedProc --
337 * This procedure is invoked when a widget command is deleted. If
338 * the widget isn't already in the process of being destroyed,
339 * this command destroys it.
345 * The widget is destroyed.
347 *----------------------------------------------------------------------
351 FrameCmdDeletedProc(clientData)
352 ClientData clientData; /* Pointer to widget record for widget. */
354 Frame *framePtr = (Frame *) clientData;
355 CkWindow *winPtr = framePtr->winPtr;
358 * This procedure could be invoked either because the window was
359 * destroyed and the command was then deleted (in which case tkwin
360 * is NULL) or because the command was deleted, and then this procedure
361 * destroys the widget.
364 if (winPtr != NULL) {
365 framePtr->winPtr = NULL;
366 Ck_DestroyWindow(winPtr);
371 *----------------------------------------------------------------------
375 * This procedure is called to process an argv/argc list, plus
376 * the option database, in order to configure (or
377 * reconfigure) a frame widget.
380 * The return value is a standard Tcl result. If TCL_ERROR is
381 * returned, then interp->result contains an error message.
384 * Configuration information, such as text string, colors, font,
385 * etc. get set for framePtr; old resources get freed, if there
388 *----------------------------------------------------------------------
392 ConfigureFrame(interp, framePtr, argc, argv, flags)
393 Tcl_Interp *interp; /* Used for error reporting. */
394 Frame *framePtr; /* Information about widget; may or may
395 * not already have values for some fields. */
396 int argc; /* Number of valid entries in argv. */
397 char **argv; /* Arguments. */
398 int flags; /* Flags to pass to Tk_ConfigureWidget. */
400 if (Ck_ConfigureWidget(interp, framePtr->winPtr, configSpecs,
401 argc, argv, (char *) framePtr, flags) != TCL_OK) {
405 Ck_SetWindowAttr(framePtr->winPtr, framePtr->fg, framePtr->bg,
407 Ck_SetInternalBorder(framePtr->winPtr, framePtr->borderPtr != NULL);
408 if ((framePtr->width > 0) || (framePtr->height > 0))
409 Ck_GeometryRequest(framePtr->winPtr, framePtr->width,
411 if ((framePtr->winPtr->flags & CK_MAPPED)
412 && !(framePtr->flags & REDRAW_PENDING)) {
413 Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
414 framePtr->flags |= REDRAW_PENDING;
420 *----------------------------------------------------------------------
424 * This procedure is invoked to display a frame widget.
430 * Commands are output to display the frame in its
433 *----------------------------------------------------------------------
437 DisplayFrame(clientData)
438 ClientData clientData; /* Information about widget. */
440 Frame *framePtr = (Frame *) clientData;
441 CkWindow *winPtr = framePtr->winPtr;
443 framePtr->flags &= ~REDRAW_PENDING;
444 if ((framePtr->winPtr == NULL) || !(winPtr->flags & CK_MAPPED)) {
447 Ck_ClearToBot(winPtr, 0, 0);
448 if (framePtr->borderPtr != NULL)
449 Ck_DrawBorder(winPtr, framePtr->borderPtr, 0, 0,
450 winPtr->width, winPtr->height);
451 Ck_EventuallyRefresh(winPtr);
455 *--------------------------------------------------------------
459 * This procedure is invoked by the dispatcher on
460 * structure changes to a frame.
466 * When the window gets deleted, internal structures get
467 * cleaned up. When it gets exposed, it is redisplayed.
469 *--------------------------------------------------------------
473 FrameEventProc(clientData, eventPtr)
474 ClientData clientData; /* Information about window. */
475 CkEvent *eventPtr; /* Information about event. */
477 Frame *framePtr = (Frame *) clientData;
479 if (eventPtr->type == CK_EV_EXPOSE && framePtr->winPtr != NULL &&
480 !(framePtr->flags & REDRAW_PENDING)) {
481 Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
482 framePtr->flags |= REDRAW_PENDING;
483 } else if (eventPtr->type == CK_EV_DESTROY) {
484 if (framePtr->winPtr != NULL) {
485 framePtr->winPtr = NULL;
486 Tcl_DeleteCommand(framePtr->interp,
487 Tcl_GetCommandName(framePtr->interp, framePtr->widgetCmd));
489 if (framePtr->flags & REDRAW_PENDING)
490 Tk_CancelIdleCall(DisplayFrame, (ClientData) framePtr);
491 Ck_EventuallyFree((ClientData) framePtr, (Ck_FreeProc *) DestroyFrame);