2 *-----------------------------------------------------------------------
5 * Implementation of a Very simple window which relies on C code for
6 * almost all of its event handlers.
8 *-----------------------------------------------------------------------
20 #include <tkIntDecls.h> not portable! (jdk)
21 this trick seems very broken on my machine so:
22 declare this thing here, and hope the linker can resolve it
24 EXTERN
int TkpUseWindow
_ANSI_ARGS_((Tcl_Interp
* interp
,
25 Tk_Window tkwin
, CONST
char * string
));
27 /* Backwards compatibility to tk8.3 and earlier */
28 #if TK_MAJOR_VERSION == 8
29 #if TK_MINOR_VERSION <= 3
30 #define Tk_SetClassProcs(a,b,c) TkSetClassProcs(a,b,c)
39 * A data structure of the following type is kept for each
40 * simple that currently exists for this process:
44 Tk_Window tkwin
; /* Window that embodies the simple. NULL
45 * means that the window has been destroyed
46 * but the data structures haven't yet been
48 Display
*display
; /* Display containing widget. Used, among
49 * other things, so that resources can be
50 * freed even after tkwin has gone away. */
51 Tcl_Interp
*interp
; /* Interpreter associated with widget. Used
52 * to delete widget command. */
53 Tcl_Command widgetCmd
; /* Token for simple's widget command. */
54 char *className
; /* Class name for widget (from configuration
55 * option). Malloc-ed. */
56 int width
; /* Width to request for window. <= 0 means
57 * don't request any size. */
58 int height
; /* Height to request for window. <= 0 means
59 * don't request any size. */
60 XColor
*background
; /* background pixel used by XClearArea */
61 char *useThis
; /* If the window is embedded, this points to
62 * the name of the window in which it is
63 * embedded (malloc'ed). For non-embedded
64 * windows this is NULL. */
65 char *exitProc
; /* Callback procedure upon window deletion. */
66 char *commandProc
; /* Callback procedure for commands sent to the window */
67 char *mydata
; /* This space for hire. */
68 int flags
; /* Various flags; see below for
73 * Flag bits for simples:
75 * GOT_FOCUS: non-zero means this widget currently has the input focus.
80 static Tk_ConfigSpec configSpecs
[] = {
81 {TK_CONFIG_COLOR
, "-background", "background", "Background",
82 "White", Tk_Offset(Simple
, background
), 0},
83 {TK_CONFIG_SYNONYM
, "-bg", "background", (char *)NULL
,
85 {TK_CONFIG_PIXELS
, "-height", "height", "Height",
86 "0", Tk_Offset(Simple
, height
), 0},
87 {TK_CONFIG_PIXELS
, "-width", "width", "Width",
88 "0", Tk_Offset(Simple
, width
), 0},
89 {TK_CONFIG_STRING
, "-use", "use", "Use",
90 "", Tk_Offset(Simple
, useThis
), TK_CONFIG_NULL_OK
},
91 {TK_CONFIG_STRING
, "-exitproc", "exitproc", "ExitProc",
92 "", Tk_Offset(Simple
, exitProc
), TK_CONFIG_NULL_OK
},
93 {TK_CONFIG_STRING
, "-commandproc", "commandproc", "CommandProc",
94 "", Tk_Offset(Simple
, commandProc
), TK_CONFIG_NULL_OK
},
95 {TK_CONFIG_STRING
, "-data", "data", "Data",
96 "", Tk_Offset(Simple
, mydata
), TK_CONFIG_NULL_OK
},
97 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
102 * Forward declarations for procedures defined later in this file:
105 static int ConfigureSimple
_ANSI_ARGS_((Tcl_Interp
*interp
,
106 Simple
*simplePtr
, int objc
, Tcl_Obj
*CONST objv
[],
108 static void DestroySimple
_ANSI_ARGS_((char *memPtr
));
109 static void SimpleCmdDeletedProc
_ANSI_ARGS_((
110 ClientData clientData
));
111 static void SimpleEventProc
_ANSI_ARGS_((ClientData clientData
,
113 static int SimpleWidgetObjCmd
_ANSI_ARGS_((ClientData clientData
,
114 Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[]));
118 *--------------------------------------------------------------
122 * This procedure is invoked to process the "simple"
126 * A standard Tcl result.
129 * See the user documentation. These procedures are just wrappers;
130 * they call ButtonCreate to do all of the real work.
132 *--------------------------------------------------------------
136 Tk_SimpleObjCmd(clientData
, interp
, objc
, objv
)
137 ClientData clientData
; /* Main window associated with
139 Tcl_Interp
*interp
; /* Current interpreter. */
140 int objc
; /* Number of arguments. */
141 Tcl_Obj
*CONST objv
[]; /* Argument objects. */
143 Tk_Window tkwin
= (Tk_Window
) clientData
;
146 char *arg
, *useOption
;
147 int i
, c
; /* , depth; (jdk) */
152 Tcl_WrongNumArgs(interp
, 1, objv
, "pathName ?options?");
157 * Pre-process the argument list. Scan through it to find any
158 * "-use" option, or the "-main" option. If the "-main" option
159 * is selected, then the application will exit if this window
164 for (i
= 2; i
< objc
; i
+= 2) {
165 arg
= Tcl_GetStringFromObj(objv
[i
], (int *) &length
);
170 if ((c
== 'u') && (strncmp(arg
, "-use", length
) == 0)) {
171 useOption
= Tcl_GetString(objv
[i
+1]);
176 * Create the window, and deal with the special option -use.
180 new = Tk_CreateWindowFromPath(interp
, tkwin
, Tcl_GetString(objv
[1]),
186 Tk_SetClass(new, "Simple");
187 if (useOption
== NULL
) {
188 useOption
= (char *)Tk_GetOption(new, "use", "Use");
190 if (useOption
!= NULL
) {
191 if (TkpUseWindow(interp
, new, useOption
) != TCL_OK
) {
197 * Create the widget record, process configuration options, and
198 * create event handlers. Then fill in a few additional fields
199 * in the widget record from the special options.
202 simplePtr
= (Simple
*) ckalloc(sizeof(Simple
));
203 simplePtr
->tkwin
= new;
204 simplePtr
->display
= Tk_Display(new);
205 simplePtr
->interp
= interp
;
206 simplePtr
->widgetCmd
= Tcl_CreateObjCommand(interp
,
207 Tk_PathName(new), SimpleWidgetObjCmd
,
208 (ClientData
) simplePtr
, SimpleCmdDeletedProc
);
209 simplePtr
->className
= NULL
;
210 simplePtr
->width
= 0;
211 simplePtr
->height
= 0;
212 simplePtr
->background
= NULL
;
213 simplePtr
->useThis
= NULL
;
214 simplePtr
->exitProc
= NULL
;
215 simplePtr
->commandProc
= NULL
;
216 simplePtr
->flags
= 0;
217 simplePtr
->mydata
= NULL
;
220 * Store backreference to simple widget in window structure.
222 Tk_SetClassProcs(new, NULL
, (ClientData
) simplePtr
);
224 /* We only handle focus and structure events, and even that might change. */
225 mask
= StructureNotifyMask
|FocusChangeMask
|NoEventMask
;
226 Tk_CreateEventHandler(new, mask
, SimpleEventProc
, (ClientData
) simplePtr
);
228 if (ConfigureSimple(interp
, simplePtr
, objc
-2, objv
+2, 0) != TCL_OK
) {
231 Tcl_SetResult(interp
, Tk_PathName(new), TCL_STATIC
);
236 Tk_DestroyWindow(new);
242 *--------------------------------------------------------------
244 * SimpleWidgetObjCmd --
246 * This procedure is invoked to process the Tcl command
247 * that corresponds to a simple widget. See the user
248 * documentation for details on what it does. If the
249 * "-commandProc" option has been set for the window,
250 * then any unknown command (neither "cget" nor "configure")
251 * will execute the command procedure first, then attempt
252 * to execute the remainder of the command as an independent
256 * A standard Tcl result.
259 * See the user documentation.
261 *--------------------------------------------------------------
265 SimpleWidgetObjCmd(clientData
, interp
, objc
, objv
)
266 ClientData clientData
; /* Information about simple widget. */
267 Tcl_Interp
*interp
; /* Current interpreter. */
268 int objc
; /* Number of arguments. */
269 Tcl_Obj
*CONST objv
[]; /* Argument objects. */
271 static char *simpleOptions
[] = {
272 "cget", "configure", (char *) NULL
275 SIMPLE_CGET
, SIMPLE_CONFIGURE
277 register Simple
*simplePtr
= (Simple
*) clientData
;
278 int result
= TCL_OK
, index
;
283 Tcl_WrongNumArgs(interp
, 1, objv
, "option ?arg arg ...?");
286 if (Tcl_GetIndexFromObj(interp
, objv
[1],
287 (CONST84
char **)simpleOptions
, "option", 0,
289 if (simplePtr
->commandProc
!= NULL
) {
290 Tcl_ResetResult(simplePtr
->interp
);
291 if (Tcl_EvalEx(simplePtr
->interp
, simplePtr
->commandProc
, -1, 0)
295 return Tcl_EvalObjv(simplePtr
->interp
, --objc
, ++objv
, TCL_EVAL_DIRECT
);
300 Tcl_Preserve((ClientData
) simplePtr
);
301 switch ((enum options
) index
) {
304 Tcl_WrongNumArgs(interp
, 2, objv
, "option");
308 result
= Tk_ConfigureValue(interp
, simplePtr
->tkwin
, configSpecs
,
309 (char *) simplePtr
, Tcl_GetString(objv
[2]), 0);
312 case SIMPLE_CONFIGURE
: {
314 result
= Tk_ConfigureInfo(interp
, simplePtr
->tkwin
, configSpecs
,
315 (char *) simplePtr
, (char *) NULL
, 0);
316 } else if (objc
== 3) {
317 result
= Tk_ConfigureInfo(interp
, simplePtr
->tkwin
, configSpecs
,
318 (char *) simplePtr
, Tcl_GetString(objv
[2]), 0);
320 for (i
= 2; i
< objc
; i
++) {
321 char *arg
= Tcl_GetStringFromObj(objv
[i
], (int *) &length
);
326 if ((c
== 'u') && (strncmp(arg
, "-use", length
) == 0)) {
327 Tcl_AppendResult(interp
, "can't modify ", arg
,
328 " option after widget is created", (char *) NULL
);
333 result
= ConfigureSimple(interp
, simplePtr
, objc
-2, objv
+2,
334 TK_CONFIG_ARGV_ONLY
);
341 Tcl_Release((ClientData
) simplePtr
);
346 *----------------------------------------------------------------------
350 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
351 * to clean up the internal structure of a simple at a safe time
352 * (when no-one is using it anymore).
358 * Everything associated with the simple is freed up.
360 *----------------------------------------------------------------------
364 DestroySimple(memPtr
)
365 char *memPtr
; /* Info about simple widget. */
367 register Simple
*simplePtr
= (Simple
*) memPtr
;
369 Tk_FreeOptions(configSpecs
, (char *) simplePtr
, simplePtr
->display
,
371 if (simplePtr
->exitProc
!= NULL
) {
372 /* Call the exit procedure */
373 Tcl_EvalEx(simplePtr
->interp
, simplePtr
->exitProc
, -1, 0);
375 ckfree((char *) simplePtr
);
379 *----------------------------------------------------------------------
383 * This procedure is called to process an objv/objc list, plus
384 * the Tk option database, in order to configure (or
385 * reconfigure) a simple widget.
388 * The return value is a standard Tcl result. If TCL_ERROR is
389 * returned, then the interp's result contains an error message.
392 * Configuration information, such as text string, colors, font,
393 * etc. get set for simplePtr; old resources get freed, if there
396 *----------------------------------------------------------------------
400 ConfigureSimple(interp
, simplePtr
, objc
, objv
, flags
)
401 Tcl_Interp
*interp
; /* Used for error reporting. */
402 register Simple
*simplePtr
; /* Information about widget; may or may
403 * not already have values for some fields. */
404 int objc
; /* Number of valid entries in objv. */
405 Tcl_Obj
*CONST objv
[]; /* Arguments. */
406 int flags
; /* Flags to pass to Tk_ConfigureWidget. */
408 /* char *oldMenuName; (jdk) */
410 if (Tk_ConfigureWidget(interp
, simplePtr
->tkwin
, configSpecs
,
411 objc
, (CONST84
char **) objv
, (char *) simplePtr
,
412 flags
| TK_CONFIG_OBJS
) != TCL_OK
) {
416 if ((simplePtr
->width
> 0) || (simplePtr
->height
> 0)) {
417 Tk_GeometryRequest(simplePtr
->tkwin
, simplePtr
->width
,
421 if (simplePtr
->background
!= NULL
) {
422 Tk_SetWindowBackground(simplePtr
->tkwin
, simplePtr
->background
->pixel
);
429 *--------------------------------------------------------------
433 * This procedure is invoked by the Tk dispatcher on
434 * structure changes to a simple. For simples with 3D
435 * borders, this procedure is also invoked for exposures.
441 * When the window gets deleted, internal structures get
442 * cleaned up. When it gets exposed, it is redisplayed.
444 *--------------------------------------------------------------
448 SimpleEventProc(clientData
, eventPtr
)
449 ClientData clientData
; /* Information about window. */
450 register XEvent
*eventPtr
; /* Information about event. */
452 register Simple
*simplePtr
= (Simple
*) clientData
;
454 if (eventPtr
->type
== DestroyNotify
) {
455 if (simplePtr
->tkwin
!= NULL
) {
458 * If this window is a container, then this event could be
459 * coming from the embedded application, in which case
460 * Tk_DestroyWindow hasn't been called yet. When Tk_DestroyWindow
461 * is called later, then another destroy event will be generated.
462 * We need to be sure we ignore the second event, since the simple
463 * could be gone by then. To do so, delete the event handler
464 * explicitly (normally it's done implicitly by Tk_DestroyWindow).
467 Tk_DeleteEventHandler(simplePtr
->tkwin
,
468 StructureNotifyMask
| FocusChangeMask
,
469 SimpleEventProc
, (ClientData
) simplePtr
);
470 simplePtr
->tkwin
= NULL
;
471 Tcl_DeleteCommandFromToken(simplePtr
->interp
, simplePtr
->widgetCmd
);
473 Tcl_EventuallyFree((ClientData
) simplePtr
, DestroySimple
);
474 } else if (eventPtr
->type
== FocusIn
) {
475 if (eventPtr
->xfocus
.detail
!= NotifyInferior
) {
476 simplePtr
->flags
|= GOT_FOCUS
;
478 } else if (eventPtr
->type
== FocusOut
) {
479 if (eventPtr
->xfocus
.detail
!= NotifyInferior
) {
480 simplePtr
->flags
&= ~GOT_FOCUS
;
487 *----------------------------------------------------------------------
489 * SimpleCmdDeletedProc --
491 * This procedure is invoked when a widget command is deleted. If
492 * the widget isn't already in the process of being destroyed,
493 * this command destroys it.
499 * The widget is destroyed.
501 *----------------------------------------------------------------------
505 SimpleCmdDeletedProc(clientData
)
506 ClientData clientData
; /* Pointer to widget record for widget. */
508 Simple
*simplePtr
= (Simple
*) clientData
;
509 Tk_Window tkwin
= simplePtr
->tkwin
;
512 * This procedure could be invoked either because the window was
513 * destroyed and the command was then deleted (in which case tkwin
514 * is NULL) or because the command was deleted, and then this procedure
515 * destroys the widget.
519 simplePtr
->tkwin
= NULL
;
520 Tk_DestroyWindow(tkwin
);
524 #endif /* TCL_WRAPPER */