4 * This module implements "frame" widgets for the Tk
5 * toolkit. Frames are windows with a background color
6 * and possibly a 3-D effect, but no other attributes.
8 * Copyright 1990 Regents of the University of California.
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
19 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkFrame.c,v 1.27 92/08/21 16:17:24 ouster Exp $ SPRITE (Berkeley)";
27 * A data structure of the following type is kept for each
28 * frame that currently exists for this process:
32 Tk_Window tkwin
; /* Window that embodies the frame. NULL
33 * means that the window has been destroyed
34 * but the data structures haven't yet been
36 Tcl_Interp
*interp
; /* Interpreter associated with
37 * widget. Used to delete widget
39 Tk_Uid screenName
; /* If this window isn't a toplevel window
40 * then this is NULL; otherwise it gives
41 * the name of the screen on which window
43 Tk_3DBorder border
; /* Structure used to draw 3-D border and
45 int borderWidth
; /* Width of 3-D border (if any). */
46 int relief
; /* 3-d effect: TK_RELIEF_RAISED etc. */
47 int width
; /* Width to request for window. <= 0 means
48 * don't request any size. */
49 int height
; /* Height to request for window. <= 0 means
50 * don't request any size. */
51 char *geometry
; /* Geometry that user requested. NULL
52 * means use width and height instead.
54 Cursor cursor
; /* Current cursor for window, or None. */
55 int flags
; /* Various flags; see below for
60 * Flag bits for frames:
62 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
63 * has already been queued to redraw
65 * CLEAR_NEEDED; Need to clear the window when redrawing.
68 #define REDRAW_PENDING 1
69 #define CLEAR_NEEDED 2
71 static Tk_ConfigSpec configSpecs
[] = {
72 {TK_CONFIG_BORDER
, "-background", "background", "Background",
73 DEF_FRAME_BG_COLOR
, Tk_Offset(Frame
, border
), TK_CONFIG_COLOR_ONLY
},
74 {TK_CONFIG_BORDER
, "-background", "background", "Background",
75 DEF_FRAME_BG_MONO
, Tk_Offset(Frame
, border
), TK_CONFIG_MONO_ONLY
},
76 {TK_CONFIG_SYNONYM
, "-bd", "borderWidth", (char *) NULL
,
78 {TK_CONFIG_SYNONYM
, "-bg", "background", (char *) NULL
,
80 {TK_CONFIG_PIXELS
, "-borderwidth", "borderWidth", "BorderWidth",
81 DEF_FRAME_BORDER_WIDTH
, Tk_Offset(Frame
, borderWidth
), 0},
82 {TK_CONFIG_ACTIVE_CURSOR
, "-cursor", "cursor", "Cursor",
83 DEF_FRAME_CURSOR
, Tk_Offset(Frame
, cursor
), TK_CONFIG_NULL_OK
},
84 {TK_CONFIG_STRING
, "-geometry", "geometry", "Geometry",
85 DEF_FRAME_GEOMETRY
, Tk_Offset(Frame
, geometry
), TK_CONFIG_NULL_OK
},
86 {TK_CONFIG_PIXELS
, "-height", "height", "Height",
87 DEF_FRAME_HEIGHT
, Tk_Offset(Frame
, height
), 0},
88 {TK_CONFIG_RELIEF
, "-relief", "relief", "Relief",
89 DEF_FRAME_RELIEF
, Tk_Offset(Frame
, relief
), 0},
90 {TK_CONFIG_PIXELS
, "-width", "width", "Width",
91 DEF_FRAME_WIDTH
, Tk_Offset(Frame
, width
), 0},
92 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
97 * Forward declarations for procedures defined later in this file:
100 static int ConfigureFrame
_ANSI_ARGS_((Tcl_Interp
*interp
,
101 Frame
*framePtr
, int argc
, char **argv
, int flags
));
102 static void DestroyFrame
_ANSI_ARGS_((ClientData clientData
));
103 static void DisplayFrame
_ANSI_ARGS_((ClientData clientData
));
104 static void FrameEventProc
_ANSI_ARGS_((ClientData clientData
,
106 static int FrameWidgetCmd
_ANSI_ARGS_((ClientData clientData
,
107 Tcl_Interp
*interp
, int argc
, char **argv
));
108 static void MapFrame
_ANSI_ARGS_((ClientData clientData
));
111 *--------------------------------------------------------------
115 * This procedure is invoked to process the "frame" and
116 * "toplevel" Tcl commands. See the user documentation for
117 * details on what it does.
120 * A standard Tcl result.
123 * See the user documentation.
125 *--------------------------------------------------------------
130 ClientData clientData
, /* Main window associated with
132 Tcl_Interp
*interp
, /* Current interpreter. */
133 int argc
, /* Number of arguments. */
134 char **argv
/* Argument strings. */
137 Tk_Window tkwin
= (Tk_Window
) clientData
;
139 register Frame
*framePtr
;
141 char *className
, *screen
;
145 Tcl_AppendResult(interp
, "wrong # args: should be \"",
146 argv
[0], " pathName ?options?\"", (char *) NULL
);
151 * The code below is a special workaround that extracts a few key
152 * options from the argument list now, rather than letting
153 * ConfigureFrame do it. This is necessary because we have
154 * to know the window's screen (if it's top-level) and its
155 * class before creating the window.
159 className
= (argv
[0][0] == 't') ? "Toplevel" : "Frame";
160 for (src
= 2, dst
= 2; src
< argc
; src
+= 2) {
165 && (strncmp(argv
[src
], "-class", strlen(argv
[src
])) == 0)) {
166 className
= argv
[src
+1];
167 } else if ((argv
[0][0] == 't') && (c
== 's')
168 && (strncmp(argv
[src
], "-screen", strlen(argv
[src
])) == 0)) {
169 screen
= argv
[src
+1];
171 argv
[dst
] = argv
[src
];
172 argv
[dst
+1] = argv
[src
+1];
179 * Provide a default screen for top-level windows (same as screen
183 if ((argv
[0][0] == 't') && (screen
== NULL
)) {
186 if (screen
!= NULL
) {
187 screenUid
= Tk_GetUid(screen
);
196 new = Tk_CreateWindowFromPath(interp
, tkwin
, argv
[1], screenUid
);
202 Tk_SetClass(new, className
);
203 framePtr
= (Frame
*) ckalloc(sizeof(Frame
));
204 framePtr
->tkwin
= new;
205 framePtr
->interp
= interp
;
206 framePtr
->screenName
= screenUid
;
207 framePtr
->border
= NULL
;
208 framePtr
->geometry
= NULL
;
209 framePtr
->cursor
= None
;
211 Tk_CreateEventHandler(framePtr
->tkwin
, ExposureMask
|StructureNotifyMask
,
212 FrameEventProc
, (ClientData
) framePtr
);
213 Tcl_CreateCommand(interp
, Tk_PathName(framePtr
->tkwin
),
214 FrameWidgetCmd
, (ClientData
) framePtr
, (void (*)(int *)) NULL
);
216 if (ConfigureFrame(interp
, framePtr
, argc
-2, argv
+2, 0) != TCL_OK
) {
217 Tk_DestroyWindow(framePtr
->tkwin
);
220 if (screenUid
!= NULL
) {
221 Tk_DoWhenIdle(MapFrame
, (ClientData
) framePtr
);
223 interp
->result
= Tk_PathName(framePtr
->tkwin
);
228 *--------------------------------------------------------------
232 * This procedure is invoked to process the Tcl command
233 * that corresponds to a frame widget. See the user
234 * documentation for details on what it does.
237 * A standard Tcl result.
240 * See the user documentation.
242 *--------------------------------------------------------------
247 ClientData clientData
, /* Information about frame widget. */
248 Tcl_Interp
*interp
, /* Current interpreter. */
249 int argc
, /* Number of arguments. */
250 char **argv
/* Argument strings. */
253 register Frame
*framePtr
= (Frame
*) clientData
;
259 Tcl_AppendResult(interp
, "wrong # args: should be \"",
260 argv
[0], " option ?arg arg ...?\"", (char *) NULL
);
263 Tk_Preserve((ClientData
) framePtr
);
265 length
= strlen(argv
[1]);
266 if ((c
== 'c') && (strncmp(argv
[1], "configure", length
) == 0)) {
268 result
= Tk_ConfigureInfo(interp
, framePtr
->tkwin
, configSpecs
,
269 (char *) framePtr
, (char *) NULL
, 0);
270 } else if (argc
== 3) {
271 result
= Tk_ConfigureInfo(interp
, framePtr
->tkwin
, configSpecs
,
272 (char *) framePtr
, argv
[2], 0);
274 result
= ConfigureFrame(interp
, framePtr
, argc
-2, argv
+2,
275 TK_CONFIG_ARGV_ONLY
);
278 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
279 "\": must be configure", (char *) NULL
);
282 Tk_Release((ClientData
) framePtr
);
287 *----------------------------------------------------------------------
291 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
292 * to clean up the internal structure of a frame at a safe time
293 * (when no-one is using it anymore).
299 * Everything associated with the frame is freed up.
301 *----------------------------------------------------------------------
306 ClientData clientData
/* Info about frame widget. */
309 register Frame
*framePtr
= (Frame
*) clientData
;
311 if (framePtr
->border
!= NULL
) {
312 Tk_Free3DBorder(framePtr
->border
);
314 if (framePtr
->geometry
!= NULL
) {
315 ckfree(framePtr
->geometry
);
317 if (framePtr
->cursor
!= None
) {
318 Tk_FreeCursor(framePtr
->cursor
);
320 ckfree((char *) framePtr
);
324 *----------------------------------------------------------------------
328 * This procedure is called to process an argv/argc list, plus
329 * the Tk option database, in order to configure (or
330 * reconfigure) a frame widget.
333 * The return value is a standard Tcl result. If TCL_ERROR is
334 * returned, then interp->result contains an error message.
337 * Configuration information, such as text string, colors, font,
338 * etc. get set for framePtr; old resources get freed, if there
341 *----------------------------------------------------------------------
346 Tcl_Interp
*interp
, /* Used for error reporting. */
347 register Frame
*framePtr
, /* Information about widget; may or may
348 * not already have values for some fields. */
349 int argc
, /* Number of valid entries in argv. */
350 char **argv
, /* Arguments. */
351 int flags
/* Flags to pass to Tk_ConfigureWidget. */
354 if (Tk_ConfigureWidget(interp
, framePtr
->tkwin
, configSpecs
,
355 argc
, argv
, (char *) framePtr
, flags
) != TCL_OK
) {
359 Tk_SetBackgroundFromBorder(framePtr
->tkwin
, framePtr
->border
);
360 Tk_SetInternalBorder(framePtr
->tkwin
, framePtr
->borderWidth
);
361 if (framePtr
->geometry
!= NULL
) {
363 if (sscanf(framePtr
->geometry
, "%dx%d", &width
, &height
) != 2) {
364 Tcl_AppendResult(interp
, "bad geometry \"", framePtr
->geometry
,
365 "\": expected widthxheight", (char *) NULL
);
368 Tk_GeometryRequest(framePtr
->tkwin
, width
, height
);
369 } else if ((framePtr
->width
> 0) && (framePtr
->height
> 0)) {
370 Tk_GeometryRequest(framePtr
->tkwin
, framePtr
->width
,
374 if (Tk_IsMapped(framePtr
->tkwin
)
375 && !(framePtr
->flags
& REDRAW_PENDING
)) {
376 Tk_DoWhenIdle(DisplayFrame
, (ClientData
) framePtr
);
377 framePtr
->flags
|= REDRAW_PENDING
|CLEAR_NEEDED
;
383 *----------------------------------------------------------------------
387 * This procedure is invoked to display a frame widget.
393 * Commands are output to X to display the frame in its
396 *----------------------------------------------------------------------
401 ClientData clientData
/* Information about widget. */
404 register Frame
*framePtr
= (Frame
*) clientData
;
405 register Tk_Window tkwin
= framePtr
->tkwin
;
407 framePtr
->flags
&= ~REDRAW_PENDING
;
408 if ((framePtr
->tkwin
== NULL
) || !Tk_IsMapped(tkwin
)) {
412 if (framePtr
->flags
& CLEAR_NEEDED
) {
413 XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
));
414 framePtr
->flags
&= ~CLEAR_NEEDED
;
416 if ((framePtr
->border
!= NULL
)
417 && (framePtr
->relief
!= TK_RELIEF_FLAT
)) {
418 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
419 framePtr
->border
, 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
),
420 framePtr
->borderWidth
, framePtr
->relief
);
425 *--------------------------------------------------------------
429 * This procedure is invoked by the Tk dispatcher on
430 * structure changes to a frame. For frames with 3D
431 * borders, this procedure is also invoked for exposures.
437 * When the window gets deleted, internal structures get
438 * cleaned up. When it gets exposed, it is redisplayed.
440 *--------------------------------------------------------------
445 ClientData clientData
, /* Information about window. */
446 register XEvent
*eventPtr
/* Information about event. */
449 register Frame
*framePtr
= (Frame
*) clientData
;
451 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
452 if ((framePtr
->relief
!= TK_RELIEF_FLAT
) && (framePtr
->tkwin
!= NULL
)
453 && !(framePtr
->flags
& REDRAW_PENDING
)) {
454 Tk_DoWhenIdle(DisplayFrame
, (ClientData
) framePtr
);
455 framePtr
->flags
|= REDRAW_PENDING
;
457 } else if (eventPtr
->type
== DestroyNotify
) {
458 Tcl_DeleteCommand(framePtr
->interp
, Tk_PathName(framePtr
->tkwin
));
459 framePtr
->tkwin
= NULL
;
460 if (framePtr
->flags
& REDRAW_PENDING
) {
461 Tk_CancelIdleCall(DisplayFrame
, (ClientData
) framePtr
);
463 Tk_CancelIdleCall(MapFrame
, (ClientData
) framePtr
);
464 Tk_EventuallyFree((ClientData
) framePtr
, DestroyFrame
);
469 *----------------------------------------------------------------------
473 * This procedure is invoked as a when-idle handler to map a
474 * newly-created top-level frame.
480 * The frame given by the clientData argument is mapped.
482 *----------------------------------------------------------------------
487 ClientData clientData
/* Pointer to frame structure. */
490 Frame
*framePtr
= (Frame
*) clientData
;
493 * Wait for all other background events to be processed before
494 * mapping window. This ensures that the window's correct geometry
495 * will have been determined before it is first mapped, so that the
496 * window manager doesn't get a false idea of its desired geometry.
500 if (Tk_DoOneEvent(TK_IDLE_EVENTS
) == 0) {
505 * After each event, make sure that the window still exists,
506 * and quit if the window has been destroyed.
509 if (framePtr
->tkwin
== NULL
) {
513 Tk_MapWindow(framePtr
->tkwin
);