OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [tags/] [start/] [insight/] [itcl/] [itk/] [generic/] [itk_archetype.c] - Blame information for rev 1765

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * ------------------------------------------------------------------------
3
 *      PACKAGE:  [incr Tk]
4
 *  DESCRIPTION:  Building mega-widgets with [incr Tcl]
5
 *
6
 *  [incr Tk] provides a framework for building composite "mega-widgets"
7
 *  using [incr Tcl] classes.  It defines a set of base classes that are
8
 *  specialized to create all other widgets.
9
 *
10
 *  This part adds C implementations for some of the methods in the
11
 *  base class itk::Archetype.
12
 *
13
 *    Itk_ArchComponentCmd   <=> itk_component
14
 *    Itk_ArchOptionCmd      <=> itk_option
15
 *    Itk_ArchInitCmd        <=> itk_initialize
16
 *    Itk_ArchCompAccessCmd  <=> component
17
 *    Itk_ArchConfigureCmd   <=> configure
18
 *    Itk_ArchCgetCmd        <=> cget
19
 *
20
 *    Itk_ArchInitOptsCmd    <=> _initOptionInfo (used to set things up)
21
 *    Itk_ArchDeleteOptsCmd  <=> _deleteOptionInfo (used to clean things up)
22
 *
23
 * ========================================================================
24
 *  AUTHOR:  Michael J. McLennan
25
 *           Bell Labs Innovations for Lucent Technologies
26
 *           mmclennan@lucent.com
27
 *           http://www.tcltk.com/itcl
28
 *
29
 *     RCS:  $Id: itk_archetype.c,v 1.1.1.1 2002-01-16 10:24:47 markom Exp $
30
 * ========================================================================
31
 *           Copyright (c) 1993-1998  Lucent Technologies, Inc.
32
 * ------------------------------------------------------------------------
33
 * See the file "license.terms" for information on usage and redistribution
34
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
35
 */
36
#include <assert.h>
37
#include "itk.h"
38
 
39
/*
40
 *  Info associated with each Archetype mega-widget:
41
 */
42
typedef struct ArchInfo {
43
    ItclObject *itclObj;        /* object containing this info */
44
    Tk_Window tkwin;            /* window representing this mega-widget */
45
    Tcl_HashTable components;   /* list of all mega-widget components */
46
    Tcl_HashTable options;      /* list of all mega-widget options */
47
    ItkOptList order;           /* gives ordering of options */
48
} ArchInfo;
49
 
50
/*
51
 *  Each component widget in an Archetype mega-widget:
52
 */
53
typedef struct ArchComponent {
54
    ItclMember *member;         /* contains protection level for this comp */
55
    Tcl_Command accessCmd;      /* access command for component widget */
56
    Tk_Window tkwin;            /* Tk window for this component widget */
57
} ArchComponent;
58
 
59
/*
60
 *  Each option in an Archetype mega-widget:
61
 */
62
typedef struct ArchOption {
63
    char *switchName;           /* command-line switch for this option */
64
    char *resName;              /* resource name in X11 database */
65
    char *resClass;             /* resource class name in X11 database */
66
    char *init;                 /* initial value for option */
67
    int flags;                  /* flags representing option state */
68
    Itcl_List parts;            /* parts relating to this option */
69
} ArchOption;
70
 
71
/*
72
 *  Flag bits for ArchOption state:
73
 */
74
#define ITK_ARCHOPT_INIT  0x01  /* option has been initialized */
75
 
76
/*
77
 *  Various parts of a composite option in an Archetype mega-widget:
78
 */
79
typedef int (Itk_ConfigOptionPartProc) _ANSI_ARGS_((Tcl_Interp *interp,
80
    ItclObject *contextObj, ClientData cdata, char* newVal));
81
 
82
typedef struct ArchOptionPart {
83
    ClientData clientData;                 /* data associated with this part */
84
    Itk_ConfigOptionPartProc *configProc;  /* update when new vals arrive */
85
    Tcl_CmdDeleteProc *deleteProc;         /* clean up after clientData */
86
 
87
    ClientData from;                       /* token that indicates who
88
                                            * contributed this option part */
89
} ArchOptionPart;
90
 
91
 
92
/*
93
 *  Info kept by the itk::option-parser namespace and shared by
94
 *  all option processing commands:
95
 */
96
typedef struct ArchMergeInfo {
97
    Tcl_HashTable usualCode;      /* usual option handling code for the
98
                                   * various widget classes */
99
 
100
    ArchInfo *archInfo;           /* internal option info for mega-widget */
101
    ArchComponent *archComp;      /* component being merged into mega-widget */
102
    Tcl_HashTable *optionTable;   /* table of valid configuration options
103
                                   * for component being merged */
104
} ArchMergeInfo;
105
 
106
/*
107
 *  Used to capture component widget configuration options when a
108
 *  new component is being merged into a mega-widget:
109
 */
110
typedef struct GenericConfigOpt {
111
    char *switchName;             /* command-line switch for this option */
112
    char *resName;                /* resource name in X11 database */
113
    char *resClass;               /* resource class name in X11 database */
114
    char *init;                   /* initial value for this option */
115
    char *value;                  /* current value for this option */
116
    char **storage;               /* storage for above strings */
117
 
118
    ArchOption *integrated;       /* integrated into this mega-widget option */
119
    ArchOptionPart *optPart;      /* integrated as this option part */
120
} GenericConfigOpt;
121
 
122
/*
123
 *  Options that are propagated by a "configure" method:
124
 */
125
typedef struct ConfigCmdline {
126
    Tcl_Obj *objv[4];           /* objects representing "configure" command */
127
} ConfigCmdline;
128
 
129
 
130
/*
131
 *  FORWARD DECLARATIONS
132
 */
133
static void Itk_DelMergeInfo _ANSI_ARGS_((char* cdata));
134
 
135
static int Itk_ArchInitOptsCmd _ANSI_ARGS_((ClientData cdata,
136
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
137
static void Itk_DelArchInfo _ANSI_ARGS_((ClientData cdata));
138
static int Itk_ArchDeleteOptsCmd _ANSI_ARGS_((ClientData cdata,
139
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
140
 
141
static int Itk_ArchComponentCmd _ANSI_ARGS_((ClientData cdata,
142
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
143
static int Itk_ArchCompAddCmd _ANSI_ARGS_((ClientData cdata,
144
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
145
static int Itk_ArchCompDeleteCmd _ANSI_ARGS_((ClientData cdata,
146
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
147
static int Itk_ArchOptKeepCmd _ANSI_ARGS_((ClientData cdata,
148
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
149
static int Itk_ArchOptIgnoreCmd _ANSI_ARGS_((ClientData cdata,
150
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
151
static int Itk_ArchOptRenameCmd _ANSI_ARGS_((ClientData cdata,
152
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
153
static int Itk_ArchOptUsualCmd _ANSI_ARGS_((ClientData cdata,
154
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
155
 
156
static int Itk_ArchInitCmd _ANSI_ARGS_((ClientData cdata,
157
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
158
static int Itk_ArchOptionCmd _ANSI_ARGS_((ClientData cdata,
159
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
160
static int Itk_ArchOptionAddCmd _ANSI_ARGS_((ClientData cdata,
161
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
162
static int Itk_ArchOptionRemoveCmd _ANSI_ARGS_((ClientData cdata,
163
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
164
 
165
static int Itk_ArchCompAccessCmd _ANSI_ARGS_((ClientData cdata,
166
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
167
static int Itk_ArchConfigureCmd _ANSI_ARGS_((ClientData cdata,
168
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
169
static int Itk_ArchCgetCmd _ANSI_ARGS_((ClientData cdata,
170
    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
171
static int Itk_PropagateOption _ANSI_ARGS_((Tcl_Interp *interp,
172
    ItclObject *contextObj, ClientData cdata, char *newval));
173
static int Itk_PropagatePublicVar _ANSI_ARGS_((Tcl_Interp *interp,
174
    ItclObject *contextObj, ClientData cdata, char *newval));
175
 
176
static int Itk_ArchSetOption _ANSI_ARGS_((Tcl_Interp *interp,
177
    ArchInfo *info, char *name, char *value));
178
static int Itk_ArchConfigOption _ANSI_ARGS_((Tcl_Interp *interp,
179
    ArchInfo *info, char *name, char *value));
180
static void Itk_ArchOptConfigError _ANSI_ARGS_((Tcl_Interp *interp,
181
    ArchInfo *info, ArchOption *archOpt));
182
static void Itk_ArchOptAccessError _ANSI_ARGS_((Tcl_Interp *interp,
183
    ArchInfo *info, ArchOption *archOpt));
184
 
185
static int Itk_GetArchInfo _ANSI_ARGS_((Tcl_Interp *interp,
186
    ItclObject* contextObj, ArchInfo **infoPtr));
187
 
188
static ArchComponent* Itk_CreateArchComponent _ANSI_ARGS_((
189
    Tcl_Interp *interp, ArchInfo *info, char *name,
190
    ItclClass *cdefn, Tcl_Command accessCmd));
191
static void Itk_DelArchComponent _ANSI_ARGS_((ArchComponent *archComp));
192
 
193
static int Itk_GetArchOption _ANSI_ARGS_((Tcl_Interp *interp,
194
    ArchInfo *info, char *switchName, char *resName, char *resClass,
195
    char *defVal, char *currVal, ArchOption **aoPtr));
196
static void Itk_InitArchOption _ANSI_ARGS_((Tcl_Interp *interp,
197
    ArchInfo *info, ArchOption *archOpt, char *defVal,
198
    char *currVal));
199
static void Itk_DelArchOption _ANSI_ARGS_((ArchOption *archOpt));
200
 
201
static ArchOptionPart* Itk_CreateOptionPart _ANSI_ARGS_((
202
    Tcl_Interp *interp, ClientData cdata, Itk_ConfigOptionPartProc* cproc,
203
    Tcl_CmdDeleteProc *dproc, ClientData from));
204
static int Itk_AddOptionPart _ANSI_ARGS_((Tcl_Interp *interp,
205
    ArchInfo *info, char *switchName, char *resName, char *resClass,
206
    char *defVal, char *currVal, ArchOptionPart *optPart,
207
    ArchOption **raOpt));
208
static ArchOptionPart* Itk_FindArchOptionPart _ANSI_ARGS_((
209
    ArchInfo *info, char *switchName, ClientData from));
210
static int Itk_RemoveArchOptionPart _ANSI_ARGS_((ArchInfo *info,
211
    char *switchName, ClientData from));
212
static int Itk_IgnoreArchOptionPart _ANSI_ARGS_((ArchInfo *info,
213
    GenericConfigOpt *opt));
214
static void Itk_DelOptionPart _ANSI_ARGS_((ArchOptionPart *optPart));
215
 
216
static ConfigCmdline* Itk_CreateConfigCmdline _ANSI_ARGS_((
217
    Tcl_Interp *interp, Tcl_Command accessCmd, char *switchName));
218
static void Itk_DeleteConfigCmdline _ANSI_ARGS_((ClientData cdata));
219
 
220
static Tcl_HashTable* Itk_CreateGenericOptTable _ANSI_ARGS_((Tcl_Interp *interp,
221
    char *options));
222
static void Itk_DelGenericOptTable _ANSI_ARGS_((Tcl_HashTable *tPtr));
223
 
224
static GenericConfigOpt* Itk_CreateGenericOpt _ANSI_ARGS_((Tcl_Interp *interp,
225
    char *switchName, Tcl_Command accessCmd));
226
static void Itk_DelGenericOpt _ANSI_ARGS_((GenericConfigOpt* opt));
227
 
228
static Tcl_HashTable* ItkGetObjsWithArchInfo _ANSI_ARGS_((Tcl_Interp *interp));
229
static void ItkFreeObjsWithArchInfo _ANSI_ARGS_((ClientData cdata,
230
    Tcl_Interp *interp));
231
 
232
 
233
/*
234
 * ------------------------------------------------------------------------
235
 *  Itk_ArchetypeInit()
236
 *
237
 *  Invoked by Itk_Init() whenever a new interpreter is created to
238
 *  declare the procedures used in the itk::Archetype base class.
239
 * ------------------------------------------------------------------------
240
 */
241
int
242
Itk_ArchetypeInit(interp)
243
    Tcl_Interp *interp;  /* interpreter to be updated */
244
{
245
    ArchMergeInfo *mergeInfo;
246
    Tcl_Namespace *parserNs;
247
 
248
    /*
249
     *  Declare all of the C routines that are integrated into
250
     *  the Archetype base class.
251
     */
252
    if (Itcl_RegisterObjC(interp,
253
            "Archetype-init", Itk_ArchInitOptsCmd,
254
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
255
 
256
        Itcl_RegisterObjC(interp,
257
            "Archetype-delete", Itk_ArchDeleteOptsCmd,
258
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
259
 
260
        Itcl_RegisterObjC(interp,
261
            "Archetype-itk_component", Itk_ArchComponentCmd,
262
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
263
 
264
        Itcl_RegisterObjC(interp,
265
            "Archetype-itk_option", Itk_ArchOptionCmd,
266
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
267
 
268
        Itcl_RegisterObjC(interp,
269
            "Archetype-itk_initialize", Itk_ArchInitCmd,
270
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
271
 
272
        Itcl_RegisterObjC(interp,
273
            "Archetype-component", Itk_ArchCompAccessCmd,
274
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
275
 
276
        Itcl_RegisterObjC(interp,
277
            "Archetype-configure",Itk_ArchConfigureCmd,
278
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK ||
279
 
280
        Itcl_RegisterObjC(interp,
281
            "Archetype-cget",Itk_ArchCgetCmd,
282
            (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL) != TCL_OK) {
283
 
284
        return TCL_ERROR;
285
    }
286
 
287
    /*
288
     *  Create the namespace containing the option parser commands.
289
     */
290
    mergeInfo = (ArchMergeInfo*)ckalloc(sizeof(ArchMergeInfo));
291
    Tcl_InitHashTable(&mergeInfo->usualCode, TCL_STRING_KEYS);
292
    mergeInfo->archInfo    = NULL;
293
    mergeInfo->archComp    = NULL;
294
    mergeInfo->optionTable = NULL;
295
 
296
    parserNs = Tcl_CreateNamespace(interp, "::itk::option-parser",
297
        (ClientData)mergeInfo, Itcl_ReleaseData);
298
 
299
    if (!parserNs) {
300
        Itk_DelMergeInfo((char*)mergeInfo);
301
        Tcl_AddErrorInfo(interp, "\n    (while initializing itk)");
302
        return TCL_ERROR;
303
    }
304
    Itcl_PreserveData((ClientData)mergeInfo);
305
    Itcl_EventuallyFree((ClientData)mergeInfo, Itk_DelMergeInfo);
306
 
307
    Tcl_CreateObjCommand(interp, "::itk::option-parser::keep",
308
        Itk_ArchOptKeepCmd,
309
        (ClientData)mergeInfo, (Tcl_CmdDeleteProc*)NULL);
310
 
311
    Tcl_CreateObjCommand(interp, "::itk::option-parser::ignore",
312
        Itk_ArchOptIgnoreCmd,
313
        (ClientData)mergeInfo, (Tcl_CmdDeleteProc*)NULL);
314
 
315
    Tcl_CreateObjCommand(interp, "::itk::option-parser::rename",
316
        Itk_ArchOptRenameCmd,
317
        (ClientData)mergeInfo, (Tcl_CmdDeleteProc*)NULL);
318
 
319
    Tcl_CreateObjCommand(interp, "::itk::option-parser::usual",
320
        Itk_ArchOptUsualCmd,
321
        (ClientData)mergeInfo, (Tcl_CmdDeleteProc*)NULL);
322
 
323
    /*
324
     *  Add the "itk::usual" command to register option handling code.
325
     */
326
    Tcl_CreateObjCommand(interp, "::itk::usual", Itk_UsualCmd,
327
        (ClientData)mergeInfo, Itcl_ReleaseData);
328
    Itcl_PreserveData((ClientData)mergeInfo);
329
 
330
    return TCL_OK;
331
}
332
 
333
 
334
/*
335
 * ------------------------------------------------------------------------
336
 *  Itk_DelMergeInfo()
337
 *
338
 *  Destroys the "merge" info record shared by commands in the
339
 *  itk::option-parser namespace.  Invoked automatically when the
340
 *  namespace containing the parsing commands is destroyed and there
341
 *  are no more uses of the data.
342
 * ------------------------------------------------------------------------
343
 */
344
static void
345
Itk_DelMergeInfo(cdata)
346
    char* cdata;  /* data to be destroyed */
347
{
348
    ArchMergeInfo *mergeInfo = (ArchMergeInfo*)cdata;
349
 
350
    Tcl_HashEntry *entry;
351
    Tcl_HashSearch place;
352
    Tcl_Obj *codePtr;
353
 
354
    assert(mergeInfo->optionTable == NULL);
355
 
356
    entry = Tcl_FirstHashEntry(&mergeInfo->usualCode, &place);
357
    while (entry) {
358
        codePtr = (Tcl_Obj*)Tcl_GetHashValue(entry);
359
        Tcl_DecrRefCount(codePtr);
360
        entry = Tcl_NextHashEntry(&place);
361
    }
362
    Tcl_DeleteHashTable(&mergeInfo->usualCode);
363
 
364
    ckfree((char*)mergeInfo);
365
}
366
 
367
 
368
/*
369
 * ------------------------------------------------------------------------
370
 *  Itk_ArchInitOptsCmd()
371
 *
372
 *  Invoked by [incr Tcl] to handle the itk::Archetype::_initOptionInfo
373
 *  method.  This method should be called out in the constructor for
374
 *  each object, to initialize the object so that it can be used with
375
 *  the other access methods in this file.  Allocates some extra
376
 *  data associated with the object at the C-language level.
377
 *
378
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
379
 * ------------------------------------------------------------------------
380
 */
381
/* ARGSUSED */
382
static int
383
Itk_ArchInitOptsCmd(dummy, interp, objc, objv)
384
    ClientData dummy;        /* unused */
385
    Tcl_Interp *interp;      /* current interpreter */
386
    int objc;                /* number of arguments */
387
    Tcl_Obj *CONST objv[];   /* argument objects */
388
{
389
    int newEntry, result;
390
    ArchInfo *info;
391
    ItclClass *contextClass;
392
    ItclObject *contextObj;
393
    Tcl_HashTable *objsWithArchInfo;
394
    Tcl_HashEntry *entry;
395
    Command *cmdPtr;
396
 
397
    if (objc != 1) {
398
        Tcl_WrongNumArgs(interp, 1, objv, "");
399
        return TCL_ERROR;
400
    }
401
 
402
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
403
        !contextObj) {
404
 
405
        char *token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
406
        Tcl_ResetResult(interp);
407
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
408
            "cannot use \"", token, "\" without an object context",
409
            (char*)NULL);
410
        return TCL_ERROR;
411
    }
412
 
413
    /*
414
     *  Create some archetype info for the current object and
415
     *  register it on the list of all known objects.
416
     */
417
    objsWithArchInfo = ItkGetObjsWithArchInfo(interp);
418
 
419
    info = (ArchInfo*)ckalloc(sizeof(ArchInfo));
420
    info->itclObj = contextObj;
421
    info->tkwin = NULL;  /* not known yet */
422
    Tcl_InitHashTable(&info->components, TCL_STRING_KEYS);
423
    Tcl_InitHashTable(&info->options, TCL_STRING_KEYS);
424
    Itk_OptListInit(&info->order, &info->options);
425
 
426
    entry = Tcl_CreateHashEntry(objsWithArchInfo, (char*)contextObj, &newEntry);
427
    if (!newEntry) {
428
        Itk_DelArchInfo( Tcl_GetHashValue(entry) );
429
    }
430
    Tcl_SetHashValue(entry, (ClientData)info);
431
 
432
    /*
433
     *  Make sure that the access command for this object
434
     *  resides in the global namespace.  If need be, move
435
     *  the command.
436
     */
437
    result = TCL_OK;
438
    cmdPtr = (Command*)contextObj->accessCmd;
439
 
440
    if (cmdPtr->nsPtr != (Namespace*)Tcl_GetGlobalNamespace(interp)) {
441
        Tcl_Obj *oldNamePtr, *newNamePtr;
442
 
443
        oldNamePtr = Tcl_NewStringObj((char*)NULL, 0);
444
        Tcl_GetCommandFullName(interp, contextObj->accessCmd, oldNamePtr);
445
        Tcl_IncrRefCount(oldNamePtr);
446
 
447
        newNamePtr = Tcl_NewStringObj("::", -1);
448
        Tcl_AppendToObj(newNamePtr,
449
            Tcl_GetCommandName(interp, contextObj->accessCmd), -1);
450
        Tcl_IncrRefCount(newNamePtr);
451
 
452
        result = TclRenameCommand(interp,
453
            Tcl_GetStringFromObj(oldNamePtr, (int*)NULL),
454
            Tcl_GetStringFromObj(newNamePtr, (int*)NULL));
455
 
456
        Tcl_DecrRefCount(oldNamePtr);
457
        Tcl_DecrRefCount(newNamePtr);
458
    }
459
 
460
    return result;
461
}
462
 
463
 
464
/*
465
 * ------------------------------------------------------------------------
466
 *  Itk_DelArchInfo()
467
 *
468
 *  Invoked when the option info associated with an itk::Archetype
469
 *  widget is no longer needed.  This usually happens when a widget
470
 *  is destroyed.  Frees the given bundle of data and removes it
471
 *  from the global list of Archetype objects.
472
 * ------------------------------------------------------------------------
473
 */
474
static void
475
Itk_DelArchInfo(cdata)
476
    ClientData cdata;    /* client data for Archetype objects */
477
{
478
    ArchInfo *info = (ArchInfo*)cdata;
479
 
480
    Tcl_HashEntry *entry;
481
    Tcl_HashSearch place;
482
    ArchOption *archOpt;
483
    ArchComponent *archComp;
484
 
485
    /*
486
     *  Destroy all component widgets.
487
     */
488
    entry = Tcl_FirstHashEntry(&info->components, &place);
489
    while (entry) {
490
        archComp = (ArchComponent*)Tcl_GetHashValue(entry);
491
        Itk_DelArchComponent(archComp);
492
        entry = Tcl_NextHashEntry(&place);
493
    }
494
    Tcl_DeleteHashTable(&info->components);
495
 
496
    /*
497
     *  Destroy all information associated with configuration options.
498
     */
499
    entry = Tcl_FirstHashEntry(&info->options, &place);
500
    while (entry) {
501
        archOpt = (ArchOption*)Tcl_GetHashValue(entry);
502
        Itk_DelArchOption(archOpt);
503
        entry = Tcl_NextHashEntry(&place);
504
    }
505
    Tcl_DeleteHashTable(&info->options);
506
    Itk_OptListFree(&info->order);
507
 
508
    ckfree((char*)info);
509
}
510
 
511
 
512
/*
513
 * ------------------------------------------------------------------------
514
 *  Itk_ArchDeleteOptsCmd()
515
 *
516
 *  Invoked by [incr Tcl] to handle the itk::Archetype::_deleteOptionInfo
517
 *  method.  This method should be called out in the destructor for each
518
 *  object, to clean up data allocated by Itk_ArchInitOptsCmd().
519
 *
520
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
521
 * ------------------------------------------------------------------------
522
 */
523
/* ARGSUSED */
524
static int
525
Itk_ArchDeleteOptsCmd(dummy, interp, objc, objv)
526
    ClientData dummy;        /* unused */
527
    Tcl_Interp *interp;      /* current interpreter */
528
    int objc;                /* number of arguments */
529
    Tcl_Obj *CONST objv[];   /* argument objects */
530
{
531
    ItclClass *contextClass;
532
    ItclObject *contextObj;
533
    Tcl_HashTable *objsWithArchInfo;
534
    Tcl_HashEntry *entry;
535
 
536
    if (objc != 1) {
537
        Tcl_WrongNumArgs(interp, 1, objv, "");
538
        return TCL_ERROR;
539
    }
540
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
541
        !contextObj) {
542
 
543
        char *token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
544
        Tcl_ResetResult(interp);
545
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
546
            "cannot use \"", token, "\" without an object context",
547
            (char*)NULL);
548
        return TCL_ERROR;
549
    }
550
 
551
    /*
552
     *  Find the info associated with this object.
553
     *  Destroy the data and remove it from the global list.
554
     */
555
    objsWithArchInfo = ItkGetObjsWithArchInfo(interp);
556
    entry = Tcl_FindHashEntry(objsWithArchInfo, (char*)contextObj);
557
 
558
    if (entry) {
559
        Itk_DelArchInfo( Tcl_GetHashValue(entry) );
560
        Tcl_DeleteHashEntry(entry);
561
    }
562
    return TCL_OK;
563
}
564
 
565
 
566
/*
567
 * ------------------------------------------------------------------------
568
 *  Itk_ArchComponentCmd()
569
 *
570
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_component
571
 *  method.  Handles the following options:
572
 *
573
 *      itk_component add ?-protected? ?-private? ?--? <name> \
574
 *          <createCmds> ?<optionCmds>?
575
 *
576
 *      itk_component delete <name> ?<name>...?
577
 *
578
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
579
 * ------------------------------------------------------------------------
580
 */
581
/* ARGSUSED */
582
static int
583
Itk_ArchComponentCmd(dummy, interp, objc, objv)
584
    ClientData dummy;        /* unused */
585
    Tcl_Interp *interp;      /* current interpreter */
586
    int objc;                /* number of arguments */
587
    Tcl_Obj *CONST objv[];   /* argument objects */
588
{
589
    char *cmd, *token, c;
590
    int length;
591
 
592
    /*
593
     *  Check arguments and handle the various options...
594
     */
595
    if (objc < 2) {
596
        cmd = Tcl_GetStringFromObj(objv[0], (int*)NULL);
597
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
598
            "wrong # args: should be one of...\n",
599
            "  ", cmd, " add ?-protected? ?-private? ?--? name createCmds ?optionCmds?\n",
600
            "  ", cmd, " delete name ?name name...?",
601
            (char*)NULL);
602
        return TCL_ERROR;
603
    }
604
 
605
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
606
    c = *token;
607
    length = strlen(token);
608
 
609
    /*
610
     *  Handle:  itk_component add...
611
     */
612
    if (c == 'a' && strncmp(token, "add", length) == 0) {
613
        if (objc < 4) {
614
            Tcl_WrongNumArgs(interp, 1, objv,
615
                "add ?-protected? ?-private? ?--? name createCmds ?optionCmds?");
616
            return TCL_ERROR;
617
        }
618
        return Itk_ArchCompAddCmd(dummy, interp, objc-1, objv+1);
619
    }
620
 
621
    /*
622
     *  Handle:  itk_component delete...
623
     */
624
    else if (c == 'd' && strncmp(token, "delete", length) == 0) {
625
        if (objc < 3) {
626
            Tcl_WrongNumArgs(interp, 1, objv, "delete name ?name name...?");
627
            return TCL_ERROR;
628
        }
629
        return Itk_ArchCompDeleteCmd(dummy, interp, objc-1, objv+1);
630
    }
631
 
632
    /*
633
     *  Flag any errors.
634
     */
635
    cmd = Tcl_GetStringFromObj(objv[0], (int*)NULL);
636
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
637
        "bad option \"", token,
638
        "\": should be one of...\n",
639
        "  ", cmd, " add name createCmds ?optionCmds?\n",
640
        "  ", cmd, " delete name ?name name...?",
641
        (char*)NULL);
642
    return TCL_ERROR;
643
}
644
 
645
 
646
/*
647
 * ------------------------------------------------------------------------
648
 *  Itk_ArchCompAddCmd()
649
 *
650
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_component
651
 *  method.  Adds a new component widget into the mega-widget,
652
 *  integrating its configuration options into the master list.
653
 *
654
 *      itk_component add ?-protected? ?-private? ?--? <name> \
655
 *          <createCmds> <optionCmds>
656
 *
657
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
658
 * ------------------------------------------------------------------------
659
 */
660
/* ARGSUSED */
661
static int
662
Itk_ArchCompAddCmd(dummy, interp, objc, objv)
663
    ClientData dummy;        /* unused */
664
    Tcl_Interp *interp;      /* current interpreter */
665
    int objc;                /* number of arguments */
666
    Tcl_Obj *CONST objv[];   /* argument objects */
667
{
668
    Tcl_HashEntry *entry = NULL;
669
    char *path = NULL;
670
    ArchComponent *archComp = NULL;
671
    ArchMergeInfo *mergeInfo = NULL;
672
    Tcl_Obj *objNamePtr = NULL;
673
    Tcl_Obj *tmpNamePtr = NULL;
674
    Tcl_Obj *winNamePtr = NULL;
675
    Tcl_Obj *hullNamePtr = NULL;
676
    int pLevel = ITCL_PUBLIC;
677
 
678
    int newEntry, result;
679
    char *cmd, *token, *name, *resultStr;
680
    Tcl_Namespace *parserNs;
681
    ItclClass *contextClass, *ownerClass;
682
    ItclObject *contextObj;
683
    ArchInfo *info;
684
    Tcl_CallFrame frame, *uplevelFramePtr, *oldFramePtr;
685
    Tcl_Command accessCmd;
686
    Tcl_Obj *objPtr;
687
    Tcl_DString buffer;
688
 
689
    /*
690
     *  Get the Archetype info associated with this widget.
691
     */
692
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
693
        !contextObj) {
694
 
695
        Tcl_ResetResult(interp);
696
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
697
            "cannot access components without an object context",
698
            (char*)NULL);
699
        return TCL_ERROR;
700
    }
701
 
702
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
703
        return TCL_ERROR;
704
    }
705
 
706
    /*
707
     *  Look for options like "-protected" or "-private".
708
     */
709
    cmd = Tcl_GetStringFromObj(objv[0], (int*)NULL);
710
 
711
    while (objc > 1) {
712
        token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
713
        if (*token != '-') {
714
            break;
715
        }
716
        else if (strcmp(token,"-protected") == 0) {
717
            pLevel = ITCL_PROTECTED;
718
        }
719
        else if (strcmp(token,"-private") == 0) {
720
            pLevel = ITCL_PRIVATE;
721
        }
722
        else if (strcmp(token,"--") == 0) {
723
            objc--;
724
            objv++;
725
            break;
726
        }
727
        else {
728
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
729
                "bad option \"", token,
730
                "\": should be -private, -protected or --",
731
                (char*)NULL);
732
            return TCL_ERROR;
733
        }
734
        objc--;
735
        objv++;
736
    }
737
 
738
    if (objc < 3 || objc > 4) {
739
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
740
            "wrong # args: should be \"", cmd,
741
            " ?-protected? ?-private? ?--? name createCmds ?optionCmds?",
742
            (char*)NULL);
743
        return TCL_ERROR;
744
    }
745
 
746
    /*
747
     *  See if a component already exists with the symbolic name.
748
     */
749
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
750
    entry = Tcl_CreateHashEntry(&info->components, name, &newEntry);
751
    if (!newEntry) {
752
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
753
            "component \"", name, "\" already defined",
754
            (char*)NULL);
755
        return TCL_ERROR;
756
    }
757
 
758
    /*
759
     *  If this component is the "hull" for the mega-widget, then
760
     *  move the object access command out of the way before
761
     *  creating the component, so it is not accidentally deleted.
762
     */
763
    Tcl_DStringInit(&buffer);
764
 
765
    objNamePtr = Tcl_NewStringObj((char*)NULL, 0);
766
    Tcl_GetCommandFullName(contextObj->classDefn->interp,
767
        contextObj->accessCmd, objNamePtr);
768
    Tcl_IncrRefCount(objNamePtr);
769
 
770
    if (strcmp(name, "hull") == 0) {
771
        tmpNamePtr = Tcl_NewStringObj((char*)NULL, 0);
772
        Tcl_GetCommandFullName(contextObj->classDefn->interp,
773
            contextObj->accessCmd, tmpNamePtr);
774
        Tcl_AppendToObj(tmpNamePtr, "-widget-", -1);
775
        Tcl_IncrRefCount(tmpNamePtr);
776
 
777
        result = TclRenameCommand(interp,
778
            Tcl_GetStringFromObj(objNamePtr, (int*)NULL),
779
            Tcl_GetStringFromObj(tmpNamePtr, (int*)NULL));
780
 
781
        if (result != TCL_OK) {
782
            goto compFail;
783
        }
784
    }
785
 
786
    /*
787
     *  Execute the <createCmds> to create the component widget.
788
     *  Do this one level up, in the scope of the calling routine.
789
     */
790
    uplevelFramePtr = _Tcl_GetCallFrame(interp, 1);
791
    oldFramePtr = _Tcl_ActivateCallFrame(interp, uplevelFramePtr);
792
 
793
      /* CYGNUS LOCAL - Fix for Tcl8.1 */
794
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
795
    if (Tcl_EvalObj(interp, objv[2]) != TCL_OK) {
796
#else
797
    if (Tcl_EvalObj(interp, objv[2], 0) != TCL_OK) {
798
#endif
799
      /* END CYGNUS LOCAL */
800
        goto compFail;
801
    }
802
 
803
    /*
804
     *  Take the result from the widget creation commands as the
805
     *  path name for the new component.  Make a local copy of
806
     *  this, since the interpreter will get used in the mean time.
807
     */
808
    resultStr = Tcl_GetStringResult(interp);
809
    path = (char*)ckalloc((unsigned)(strlen(resultStr)+1));
810
    strcpy(path, resultStr);
811
 
812
    /*
813
     *  Look for the access command token in the context of the
814
     *  calling namespace.  By-pass any protection at this point.
815
     */
816
    accessCmd = Tcl_FindCommand(interp, path, (Tcl_Namespace*)NULL,
817
        /* flags */ 0);
818
 
819
    if (!accessCmd) {
820
        Tcl_ResetResult(interp);
821
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
822
           "cannot find component access command \"",
823
            path, "\" for component \"", name, "\"",
824
            (char*)NULL);
825
        goto compFail;
826
    }
827
 
828
    winNamePtr = Tcl_NewStringObj((char*)NULL, 0);
829
    Tcl_GetCommandFullName(interp, accessCmd, winNamePtr);
830
    Tcl_IncrRefCount(winNamePtr);
831
 
832
    (void) _Tcl_ActivateCallFrame(interp, oldFramePtr);
833
 
834
    /*
835
     *  Create the component record.  Set the protection level
836
     *  according to the "-protected" or "-private" option.
837
     */
838
    ownerClass = contextClass;
839
    uplevelFramePtr = _Tcl_GetCallFrame(interp, 1);
840
    if (uplevelFramePtr && Itcl_IsClassNamespace(uplevelFramePtr->nsPtr)) {
841
        ownerClass = (ItclClass*)uplevelFramePtr->nsPtr->clientData;
842
    }
843
 
844
    archComp = Itk_CreateArchComponent(interp, info, name, ownerClass,
845
        accessCmd);
846
 
847
    if (!archComp) {
848
        goto compFail;
849
    }
850
 
851
    Tcl_SetHashValue(entry, (ClientData)archComp);
852
    archComp->member->protection = pLevel;
853
 
854
    /*
855
     *  If this component is the "hull" for the mega-widget, then
856
     *  move the hull widget access command to a different name,
857
     *  and move the object access command back into place.  This
858
     *  way, when the widget name is used as a command, the object
859
     *  access command will handle all requests.
860
     */
861
    if (strcmp(name, "hull") == 0) {
862
        hullNamePtr = Tcl_NewStringObj((char*)NULL, 0);
863
        Tcl_GetCommandFullName(interp, accessCmd, hullNamePtr);
864
        Tcl_AppendToObj(hullNamePtr, "-itk_hull", -1);
865
        Tcl_IncrRefCount(hullNamePtr);
866
 
867
        result = TclRenameCommand(interp,
868
            Tcl_GetStringFromObj(winNamePtr, (int*)NULL),
869
            Tcl_GetStringFromObj(hullNamePtr, (int*)NULL));
870
 
871
        if (result != TCL_OK) {
872
            goto compFail;
873
        }
874
 
875
        Tcl_DecrRefCount(winNamePtr);  /* winNamePtr keeps current name */
876
        winNamePtr = hullNamePtr;
877
        hullNamePtr = NULL;
878
 
879
        result = TclRenameCommand(interp,
880
            Tcl_GetStringFromObj(tmpNamePtr, (int*)NULL),
881
            Tcl_GetStringFromObj(objNamePtr, (int*)NULL));
882
 
883
        if (result != TCL_OK) {
884
            goto compFail;
885
        }
886
    }
887
 
888
    /*
889
     *  Add a binding onto the new component, so that when its
890
     *  window is destroyed, it will automatically remove itself
891
     *  from its parent's component list.  Avoid doing these things
892
     *  for the "hull" component, since it is a special case and
893
     *  these things are not really necessary.
894
     */
895
    else {
896
        Tcl_DStringSetLength(&buffer, 0);
897
        Tcl_DStringAppend(&buffer, "bindtags ", -1);
898
        Tcl_DStringAppend(&buffer, path, -1);
899
        if (Tcl_Eval(interp, Tcl_DStringValue(&buffer)) != TCL_OK) {
900
            goto compFail;
901
        }
902
 
903
        Tcl_DStringSetLength(&buffer, 0);
904
        Tcl_DStringAppend(&buffer, "bind itk-destroy-", -1);
905
        Tcl_DStringAppend(&buffer, path, -1);
906
        Tcl_DStringAppend(&buffer, " <Destroy> [itcl::code ", -1);
907
 
908
        Tcl_DStringAppend(&buffer,
909
            Tcl_GetStringFromObj(objNamePtr,(int*)NULL), -1);
910
 
911
        Tcl_DStringAppend(&buffer, " itk_component delete ", -1);
912
        Tcl_DStringAppend(&buffer, name, -1);
913
        Tcl_DStringAppend(&buffer, "]\n", -1);
914
        Tcl_DStringAppend(&buffer, "bindtags ", -1);
915
        Tcl_DStringAppend(&buffer, path, -1);
916
        Tcl_DStringAppend(&buffer, " {itk-destroy-", -1);
917
        Tcl_DStringAppend(&buffer, path, -1);
918
        Tcl_DStringAppend(&buffer, " ", -1);
919
        Tcl_DStringAppend(&buffer, Tcl_GetStringResult(interp), -1);
920
        Tcl_DStringAppend(&buffer, "}", -1);
921
        if (Tcl_Eval(interp, Tcl_DStringValue(&buffer)) != TCL_OK) {
922
            goto compFail;
923
        }
924
    }
925
 
926
    /*
927
     *  Query the list of configuration options for this widget,
928
     *  so we will know which ones are valid.  Build an option
929
     *  table to represent these, so they can be found quickly
930
     *  by the option parsing commands in "itk::option-parser".
931
     */
932
    Tcl_DStringTrunc(&buffer, 0);
933
    Tcl_DStringAppendElement(&buffer,
934
        Tcl_GetStringFromObj(winNamePtr, (int*)NULL));
935
    Tcl_DStringAppendElement(&buffer, "configure");
936
 
937
    result = Tcl_Eval(interp, Tcl_DStringValue(&buffer));
938
 
939
    if (result != TCL_OK) {
940
        goto compFail;
941
    }
942
    Tcl_DStringSetLength(&buffer, 0);
943
    Tcl_DStringAppend(&buffer, Tcl_GetStringResult(interp), -1);
944
 
945
    /*
946
     *  Find the "itk::option-parser" namespace and get the data
947
     *  record shared by all of the parsing commands.
948
     */
949
    parserNs = Tcl_FindNamespace(interp, "::itk::option-parser",
950
        (Tcl_Namespace*)NULL, TCL_LEAVE_ERR_MSG);
951
 
952
    if (!parserNs) {
953
        goto compFail;
954
    }
955
    mergeInfo = (ArchMergeInfo*)parserNs->clientData;
956
    assert(mergeInfo);
957
 
958
    /*
959
     *  Initialize the data record used by the option parsing commands.
960
     *  Store a table of valid configuration options, along with the
961
     *  info for the mega-widget that is being updated.
962
     */
963
    mergeInfo->optionTable = Itk_CreateGenericOptTable(interp,
964
        Tcl_DStringValue(&buffer));
965
 
966
    if (!mergeInfo->optionTable) {
967
        goto compFail;
968
    }
969
    mergeInfo->archInfo = info;
970
    mergeInfo->archComp = archComp;
971
 
972
    /*
973
     *  Execute the option-handling commands in the "itk::option-parser"
974
     *  namespace.  If there are no option-handling commands, invoke
975
     *  the "usual" command instead.
976
     */
977
    if (objc != 4) {
978
        objPtr = Tcl_NewStringObj("usual", -1);
979
        Tcl_IncrRefCount(objPtr);
980
    } else {
981
        objPtr = objv[3];
982
    }
983
 
984
    result = Tcl_PushCallFrame(interp, &frame,
985
        parserNs, /* isProcCallFrame */ 0);
986
 
987
    if (result == TCL_OK) {
988
      /* CYGNUS LOCAL - Fix for Tcl8.1 */
989
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
990
      result = Tcl_EvalObj(interp, objPtr);
991
#else
992
      result = Tcl_EvalObj(interp, objPtr, 0);
993
#endif
994
      /* END CYGNUS LOCAL */
995
      Tcl_PopCallFrame(interp);
996
    }
997
 
998
    if (objPtr != objv[3]) {
999
        Tcl_DecrRefCount(objPtr);
1000
    }
1001
    if (result != TCL_OK) {
1002
        goto compFail;
1003
    }
1004
 
1005
    Itk_DelGenericOptTable(mergeInfo->optionTable);
1006
    mergeInfo->optionTable = NULL;
1007
    mergeInfo->archInfo    = NULL;
1008
    mergeInfo->archComp    = NULL;
1009
 
1010
    ckfree(path);
1011
 
1012
    Tcl_DStringFree(&buffer);
1013
    if (objNamePtr) {
1014
        Tcl_DecrRefCount(objNamePtr);
1015
    }
1016
    if (tmpNamePtr) {
1017
        Tcl_DecrRefCount(tmpNamePtr);
1018
    }
1019
    if (winNamePtr) {
1020
        Tcl_DecrRefCount(winNamePtr);
1021
    }
1022
    if (hullNamePtr) {
1023
        Tcl_DecrRefCount(hullNamePtr);
1024
    }
1025
 
1026
    Tcl_SetResult(interp, name, TCL_VOLATILE);
1027
    return TCL_OK;
1028
 
1029
    /*
1030
     *  If any errors were encountered, clean up and return.
1031
     */
1032
compFail:
1033
    if (archComp) {
1034
        Itk_DelArchComponent(archComp);
1035
    }
1036
    if (entry) {
1037
        Tcl_DeleteHashEntry(entry);
1038
    }
1039
    if (path) {
1040
        ckfree(path);
1041
    }
1042
    if (mergeInfo && mergeInfo->optionTable) {
1043
        Itk_DelGenericOptTable(mergeInfo->optionTable);
1044
        mergeInfo->optionTable = NULL;
1045
        mergeInfo->archInfo    = NULL;
1046
        mergeInfo->archComp    = NULL;
1047
    }
1048
 
1049
    Tcl_DStringFree(&buffer);
1050
    if (objNamePtr) {
1051
        Tcl_DecrRefCount(objNamePtr);
1052
    }
1053
    if (tmpNamePtr) {
1054
        Tcl_DecrRefCount(tmpNamePtr);
1055
    }
1056
    if (winNamePtr) {
1057
        Tcl_DecrRefCount(winNamePtr);
1058
    }
1059
    if (hullNamePtr) {
1060
        Tcl_DecrRefCount(hullNamePtr);
1061
    }
1062
 
1063
    /*
1064
     *  Add error info and return.
1065
     */
1066
    objPtr = Tcl_NewStringObj((char*)NULL, 0);
1067
    Tcl_AppendToObj(objPtr, "\n    (while creating component \"", -1);
1068
    Tcl_AppendToObj(objPtr, name, -1);
1069
    Tcl_AppendToObj(objPtr, "\" for widget \"", -1);
1070
    Tcl_GetCommandFullName(contextObj->classDefn->interp,
1071
        contextObj->accessCmd, objPtr);
1072
    Tcl_AppendToObj(objPtr, "\")", -1);
1073
    Tcl_IncrRefCount(objPtr);
1074
 
1075
    Tcl_AddErrorInfo(interp, Tcl_GetStringFromObj(objPtr, (int*)NULL));
1076
    Tcl_DecrRefCount(objPtr);
1077
 
1078
 
1079
    return TCL_ERROR;
1080
}
1081
 
1082
 
1083
/*
1084
 * ------------------------------------------------------------------------
1085
 *  Itk_ArchCompDeleteCmd()
1086
 *
1087
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_component
1088
 *  method.  Removes an existing component widget from a mega-widget,
1089
 *  and removes any configuration options associated with it.
1090
 *
1091
 *      itk_component delete <name> ?<name> <name>...?
1092
 *
1093
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1094
 * ------------------------------------------------------------------------
1095
 */
1096
/* ARGSUSED */
1097
static int
1098
Itk_ArchCompDeleteCmd(dummy, interp, objc, objv)
1099
    ClientData dummy;        /* unused */
1100
    Tcl_Interp *interp;      /* current interpreter */
1101
    int objc;                /* number of arguments */
1102
    Tcl_Obj *CONST objv[];   /* argument objects */
1103
{
1104
    int i;
1105
    char *token;
1106
    ItclClass *contextClass;
1107
    ItclObject *contextObj;
1108
    ArchInfo *info;
1109
    Tcl_HashEntry *entry;
1110
    Tcl_HashSearch place;
1111
    Itcl_ListElem *elem;
1112
    ArchComponent *archComp;
1113
    ArchOption *archOpt;
1114
    ArchOptionPart *optPart;
1115
 
1116
    /*
1117
     *  Get the Archetype info associated with this widget.
1118
     */
1119
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
1120
        !contextObj) {
1121
 
1122
        Tcl_ResetResult(interp);
1123
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1124
            "cannot access components without an object context",
1125
            (char*)NULL);
1126
        return TCL_ERROR;
1127
    }
1128
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
1129
        return TCL_ERROR;
1130
    }
1131
 
1132
    /*
1133
     *  Scan through the list of component names and delete each
1134
     *  one.  Make sure that each component exists.
1135
     */
1136
    for (i=1; i < objc; i++) {
1137
        token = Tcl_GetStringFromObj(objv[i], (int*)NULL);
1138
        entry = Tcl_FindHashEntry(&info->components, token);
1139
        if (!entry) {
1140
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1141
                "name \"", token, "\" is not a component",
1142
                (char*)NULL);
1143
            return TCL_ERROR;
1144
        }
1145
        archComp = (ArchComponent*)Tcl_GetHashValue(entry);
1146
        Tcl_DeleteHashEntry(entry);
1147
 
1148
        entry = Tcl_FirstHashEntry(&info->options, &place);
1149
        while (entry) {
1150
            archOpt = (ArchOption*)Tcl_GetHashValue(entry);
1151
            elem = Itcl_FirstListElem(&archOpt->parts);
1152
            while (elem) {
1153
                optPart = (ArchOptionPart*)Itcl_GetListValue(elem);
1154
                if (optPart->from == (ClientData)archComp) {
1155
                    Itk_DelOptionPart(optPart);
1156
                    elem = Itcl_DeleteListElem(elem);
1157
                }
1158
                else {
1159
                    elem = Itcl_NextListElem(elem);
1160
                }
1161
            }
1162
            entry = Tcl_NextHashEntry(&place);
1163
        }
1164
 
1165
        Itk_DelArchComponent(archComp);
1166
    }
1167
    return TCL_OK;
1168
}
1169
 
1170
 
1171
/*
1172
 * ------------------------------------------------------------------------
1173
 *  Itk_ArchOptKeepCmd()
1174
 *
1175
 *  Invoked by [incr Tcl] to handle the "keep" command in the itk
1176
 *  option parser.  Integrates a list of component configuration options
1177
 *  into a mega-widget, so that whenever the mega-widget is updated,
1178
 *  the component will be updated as well.
1179
 *
1180
 *  Handles the following syntax:
1181
 *
1182
 *      keep <option> ?<option>...?
1183
 *
1184
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1185
 * ------------------------------------------------------------------------
1186
 */
1187
/* ARGSUSED */
1188
static int
1189
Itk_ArchOptKeepCmd(clientData, interp, objc, objv)
1190
    ClientData clientData;   /* option merging info record */
1191
    Tcl_Interp *interp;      /* current interpreter */
1192
    int objc;                /* number of arguments */
1193
    Tcl_Obj *CONST objv[];   /* argument objects */
1194
{
1195
    ArchMergeInfo *mergeInfo = (ArchMergeInfo*)clientData;
1196
    int result = TCL_OK;
1197
 
1198
    int i;
1199
    char *token;
1200
    Tcl_HashEntry *entry;
1201
    GenericConfigOpt *opt;
1202
    ArchOption *archOpt;
1203
    ArchOptionPart *optPart;
1204
    ConfigCmdline *cmdlinePtr;
1205
 
1206
    if (objc < 2) {
1207
        Tcl_WrongNumArgs(interp, 1, objv, "option ?option...?");
1208
        return TCL_ERROR;
1209
    }
1210
 
1211
    /*
1212
     *  Make sure that this command is being accessed in the
1213
     *  proper context.  The merge info record should be set up
1214
     *  properly.
1215
     */
1216
    if (!mergeInfo->archInfo || !mergeInfo->optionTable) {
1217
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1218
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1219
            "improper usage: \"", token,
1220
            "\" should only be accessed via itk_component",
1221
            (char*)NULL);
1222
        return TCL_ERROR;
1223
    }
1224
 
1225
    /*
1226
     *  Scan through all of the options on the list, and make
1227
     *  sure that they are valid options for this component.
1228
     *  Integrate them into the option info for the mega-widget.
1229
     */
1230
    for (i=1; i < objc; i++) {
1231
        token = Tcl_GetStringFromObj(objv[i], (int*)NULL);
1232
        entry = Tcl_FindHashEntry(mergeInfo->optionTable, token);
1233
        if (!entry) {
1234
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1235
                "option not recognized: ", token,
1236
                (char*)NULL);
1237
            result = TCL_ERROR;
1238
            break;
1239
        }
1240
        opt = (GenericConfigOpt*)Tcl_GetHashValue(entry);
1241
 
1242
        /*
1243
         *  If this option has already been integrated, then
1244
         *  remove it and start again.
1245
         */
1246
        Itk_IgnoreArchOptionPart(mergeInfo->archInfo, opt);
1247
 
1248
        /*
1249
         *  Build a command prefix that can be used to apply changes
1250
         *  to this option for this component.
1251
         */
1252
        cmdlinePtr = Itk_CreateConfigCmdline(interp,
1253
            mergeInfo->archComp->accessCmd, token);
1254
 
1255
        optPart = Itk_CreateOptionPart(interp, (ClientData)cmdlinePtr,
1256
            Itk_PropagateOption, Itk_DeleteConfigCmdline,
1257
            (ClientData)mergeInfo->archComp);
1258
 
1259
        result = Itk_AddOptionPart(interp, mergeInfo->archInfo,
1260
            opt->switchName, opt->resName, opt->resClass,
1261
            opt->init, opt->value, optPart, &archOpt);
1262
 
1263
        if (result == TCL_OK) {
1264
            opt->integrated = archOpt;
1265
            opt->optPart    = optPart;
1266
        } else {
1267
            Itk_DelOptionPart(optPart);
1268
            result = TCL_ERROR;
1269
            break;
1270
        }
1271
    }
1272
    return result;
1273
}
1274
 
1275
 
1276
/*
1277
 * ------------------------------------------------------------------------
1278
 *  Itk_ArchOptIgnoreCmd()
1279
 *
1280
 *  Invoked by [incr Tcl] to handle the "ignore" command in the itk
1281
 *  option parser.  Removes a list of component configuration options
1282
 *  from a mega-widget.  This negates the action of previous "keep"
1283
 *  and "rename" commands.
1284
 *
1285
 *  Handles the following syntax:
1286
 *
1287
 *      ignore <option> ?<option>...?
1288
 *
1289
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1290
 * ------------------------------------------------------------------------
1291
 */
1292
/* ARGSUSED */
1293
static int
1294
Itk_ArchOptIgnoreCmd(clientData, interp, objc, objv)
1295
    ClientData clientData;   /* option merging info record */
1296
    Tcl_Interp *interp;      /* current interpreter */
1297
    int objc;                /* number of arguments */
1298
    Tcl_Obj *CONST objv[];   /* argument objects */
1299
{
1300
    ArchMergeInfo *mergeInfo = (ArchMergeInfo*)clientData;
1301
 
1302
    int i;
1303
    char *token;
1304
    Tcl_HashEntry *entry;
1305
    GenericConfigOpt *opt;
1306
 
1307
    if (objc < 2) {
1308
        Tcl_WrongNumArgs(interp, 1, objv, "option ?option...?");
1309
        return TCL_ERROR;
1310
    }
1311
 
1312
    /*
1313
     *  Make sure that this command is being accessed in the
1314
     *  proper context.  The merge info record should be set up
1315
     *  properly.
1316
     */
1317
    if (!mergeInfo->archInfo || !mergeInfo->optionTable) {
1318
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1319
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1320
            "improper usage: \"", token,
1321
            "\" should only be accessed via itk_component",
1322
            (char*)NULL);
1323
        return TCL_ERROR;
1324
    }
1325
 
1326
    /*
1327
     *  Scan through all of the options on the list, and make
1328
     *  sure that they are valid options for this component.
1329
     *  Remove them from the mega-widget.
1330
     */
1331
    for (i=1; i < objc; i++) {
1332
        token = Tcl_GetStringFromObj(objv[i], (int*)NULL);
1333
        entry = Tcl_FindHashEntry(mergeInfo->optionTable, token);
1334
        if (!entry) {
1335
            Tcl_AppendResult(interp, "option not recognized: ", token,
1336
                (char*)NULL);
1337
            return TCL_ERROR;
1338
        }
1339
        opt = (GenericConfigOpt*)Tcl_GetHashValue(entry);
1340
 
1341
        /*
1342
         *  If this option has already been integrated, then
1343
         *  remove it.  Otherwise, ignore it.
1344
         */
1345
        Itk_IgnoreArchOptionPart(mergeInfo->archInfo, opt);
1346
    }
1347
    return TCL_OK;
1348
}
1349
 
1350
 
1351
/*
1352
 * ------------------------------------------------------------------------
1353
 *  Itk_ArchOptRenameCmd()
1354
 *
1355
 *  Invoked by [incr Tcl] to handle the "rename" command in the itk
1356
 *  option parser.  Integrates one configuration option into a
1357
 *  mega-widget, using a different name for the option.  Whenever the
1358
 *  mega-widget option is updated, the renamed option will be updated
1359
 *  as well.  Handles the following syntax:
1360
 *
1361
 *      rename <oldSwitch> <newSwitch> <resName> <resClass>
1362
 *
1363
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1364
 * ------------------------------------------------------------------------
1365
 */
1366
/* ARGSUSED */
1367
static int
1368
Itk_ArchOptRenameCmd(clientData, interp, objc, objv)
1369
    ClientData clientData;   /* option merging info record */
1370
    Tcl_Interp *interp;      /* current interpreter */
1371
    int objc;                /* number of arguments */
1372
    Tcl_Obj *CONST objv[];   /* argument objects */
1373
{
1374
    ArchMergeInfo *mergeInfo = (ArchMergeInfo*)clientData;
1375
 
1376
    int result;
1377
    char *oldSwitch, *newSwitch, *resName, *resClass;
1378
    Tcl_HashEntry *entry;
1379
    GenericConfigOpt *opt;
1380
    ArchOption *archOpt;
1381
    ArchOptionPart *optPart;
1382
    ConfigCmdline *cmdlinePtr;
1383
 
1384
    if (objc != 5) {
1385
        Tcl_WrongNumArgs(interp, 1, objv,
1386
            "oldSwitch newSwitch resourceName resourceClass");
1387
        return TCL_ERROR;
1388
    }
1389
 
1390
    /*
1391
     *  Make sure that this command is being accessed in the
1392
     *  proper context.  The merge info record should be set up
1393
     *  properly.
1394
     */
1395
    if (!mergeInfo->archInfo || !mergeInfo->optionTable) {
1396
        char *token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1397
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1398
            "improper usage: \"", token,
1399
            "\" should only be accessed via itk_component",
1400
            (char*)NULL);
1401
        return TCL_ERROR;
1402
    }
1403
 
1404
    oldSwitch = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1405
    newSwitch = Tcl_GetStringFromObj(objv[2], (int*)NULL);
1406
    resName   = Tcl_GetStringFromObj(objv[3], (int*)NULL);
1407
    resClass  = Tcl_GetStringFromObj(objv[4], (int*)NULL);
1408
 
1409
    /*
1410
     *  Make sure that the resource name and resource class look good.
1411
     */
1412
    if (!islower((int)*resName)) {
1413
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1414
            "bad resource name \"", resName,
1415
            "\": should start with a lower case letter",
1416
            (char*)NULL);
1417
        return TCL_ERROR;
1418
    }
1419
    if (!isupper((int)*resClass)) {
1420
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1421
            "bad resource class \"", resClass,
1422
            "\": should start with an upper case letter",
1423
            (char*)NULL);
1424
        return TCL_ERROR;
1425
    }
1426
 
1427
    /*
1428
     *  Make sure that the specified switch exists in the widget.
1429
     */
1430
    entry = Tcl_FindHashEntry(mergeInfo->optionTable, oldSwitch);
1431
    if (!entry) {
1432
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1433
            "option not recognized: ", oldSwitch,
1434
            (char*)NULL);
1435
        return TCL_ERROR;
1436
    }
1437
    opt = (GenericConfigOpt*)Tcl_GetHashValue(entry);
1438
 
1439
    /*
1440
     *  If this option has already been integrated, then
1441
     *  remove it and start again.
1442
     */
1443
    Itk_IgnoreArchOptionPart(mergeInfo->archInfo, opt);
1444
 
1445
    /*
1446
     *  Build a command prefix that can be used to apply changes
1447
     *  to this option for this component.
1448
     */
1449
    cmdlinePtr = Itk_CreateConfigCmdline(interp,
1450
        mergeInfo->archComp->accessCmd, oldSwitch);
1451
 
1452
    optPart = Itk_CreateOptionPart(interp, (ClientData)cmdlinePtr,
1453
        Itk_PropagateOption, Itk_DeleteConfigCmdline,
1454
        (ClientData)mergeInfo->archComp);
1455
 
1456
    /*
1457
     *  Merge this option into the mega-widget with a new name.
1458
     */
1459
    result = Itk_AddOptionPart(interp, mergeInfo->archInfo, newSwitch,
1460
        resName, resClass, opt->init, opt->value, optPart,
1461
        &archOpt);
1462
 
1463
    if (result == TCL_OK) {
1464
        opt->integrated = archOpt;
1465
        opt->optPart    = optPart;
1466
    } else {
1467
        Itk_DelOptionPart(optPart);
1468
        result = TCL_ERROR;
1469
    }
1470
    return result;
1471
}
1472
 
1473
 
1474
/*
1475
 * ------------------------------------------------------------------------
1476
 *  Itk_ArchOptUsualCmd()
1477
 *
1478
 *  Invoked by [incr Tcl] to handle the "usual" command in the itk
1479
 *  option parser.  Looks for a set of "usual" option-handling commands
1480
 *  associated with the given tag or component class and then evaluates
1481
 *  the commands in the option parser namespace.  This keeps the user
1482
 *  from having to type a bunch of "keep" and "rename" commands for
1483
 *  each component widget.
1484
 *
1485
 *  Handles the following syntax:
1486
 *
1487
 *      usual ?<tag>?
1488
 *
1489
 *  If the <tag> is not specified, then the class name for the
1490
 *  component is used as the tag name.
1491
 *
1492
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1493
 * ------------------------------------------------------------------------
1494
 */
1495
/* ARGSUSED */
1496
static int
1497
Itk_ArchOptUsualCmd(clientData, interp, objc, objv)
1498
    ClientData clientData;   /* option merging info record */
1499
    Tcl_Interp *interp;      /* current interpreter */
1500
    int objc;                /* number of arguments */
1501
    Tcl_Obj *CONST objv[];   /* argument objects */
1502
{
1503
    ArchMergeInfo *mergeInfo = (ArchMergeInfo*)clientData;
1504
 
1505
    char *tag;
1506
    Tcl_HashEntry *entry;
1507
    Tcl_Obj *codePtr;
1508
 
1509
    if (objc > 2) {
1510
        Tcl_WrongNumArgs(interp, 1, objv, "?tag?");
1511
        return TCL_ERROR;
1512
    }
1513
 
1514
    /*
1515
     *  Make sure that this command is being accessed in the
1516
     *  proper context.  The merge info record should be set up
1517
     *  properly.
1518
     */
1519
    if (!mergeInfo->archInfo || !mergeInfo->optionTable) {
1520
        char *token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1521
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1522
            "improper usage: \"", token,
1523
            "\" should only be accessed via itk_component",
1524
            (char*)NULL);
1525
        return TCL_ERROR;
1526
    }
1527
 
1528
    /*
1529
     *  If a tag name was specified, then use this to look up
1530
     *  the "usual" code.  Otherwise, use the class name for
1531
     *  the component widget.
1532
     */
1533
    if (objc == 2) {
1534
        tag = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1535
    } else {
1536
        tag = Tk_Class(mergeInfo->archComp->tkwin);
1537
    }
1538
 
1539
    /*
1540
     *  Look for some code associated with the tag and evaluate
1541
     *  it in the current context.
1542
     */
1543
    entry = Tcl_FindHashEntry(&mergeInfo->usualCode, tag);
1544
    if (entry) {
1545
        codePtr = (Tcl_Obj*)Tcl_GetHashValue(entry);
1546
      /* CYGNUS LOCAL - Fix for Tcl8.1 */
1547
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
1548
        return Tcl_EvalObj(interp, codePtr);
1549
#else
1550
        return Tcl_EvalObj(interp, codePtr, 0);
1551
#endif
1552
      /* END CYGNUS LOCAL */
1553
    }
1554
 
1555
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1556
        "can't find usual code for tag \"", tag, "\"",
1557
        (char*)NULL);
1558
    return TCL_ERROR;
1559
}
1560
 
1561
 
1562
/*
1563
 * ------------------------------------------------------------------------
1564
 *  Itk_UsualCmd()
1565
 *
1566
 *  Invoked by [incr Tcl] to handle the "usual" command in the ::itk
1567
 *  namespace.  Used to query or set the option-handling code associated
1568
 *  with a widget class or arbitrary tag name.  This code is later
1569
 *  used by the "usual" command in the "itk::option-parser" namespace.
1570
 *
1571
 *  Handles the following syntax:
1572
 *
1573
 *      usual ?<tag>? ?<code>?
1574
 *
1575
 *  If the <tag> is not specified, then this returns a list of all
1576
 *  known tags.  If the <code> is not specified, then this returns
1577
 *  the current code associated with <tag>, or an empty string if
1578
 *  <tag> is not recognized.  Otherwise, it sets the code fragment
1579
 *  for <tag> to <code>.
1580
 *
1581
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1582
 * ------------------------------------------------------------------------
1583
 */
1584
/* ARGSUSED */
1585
int
1586
Itk_UsualCmd(clientData, interp, objc, objv)
1587
    ClientData clientData;   /* option merging info record */
1588
    Tcl_Interp *interp;      /* current interpreter */
1589
    int objc;                /* number of arguments */
1590
    Tcl_Obj *CONST objv[];   /* argument objects */
1591
{
1592
    ArchMergeInfo *mergeInfo = (ArchMergeInfo*)clientData;
1593
 
1594
    int newEntry;
1595
    char *tag, *token;
1596
    Tcl_HashEntry *entry;
1597
    Tcl_HashSearch place;
1598
    Tcl_Obj *codePtr;
1599
 
1600
    if (objc > 3) {
1601
        Tcl_WrongNumArgs(interp, 1, objv, "?tag? ?commands?");
1602
        return TCL_ERROR;
1603
    }
1604
 
1605
    /*
1606
     *  If no arguments were specified, then return a list of
1607
     *  all known tags.
1608
     */
1609
    if (objc == 1) {
1610
        entry = Tcl_FirstHashEntry(&mergeInfo->usualCode, &place);
1611
        while (entry) {
1612
            tag = Tcl_GetHashKey(&mergeInfo->usualCode, entry);
1613
            Tcl_AppendElement(interp, tag);
1614
            entry = Tcl_NextHashEntry(&place);
1615
        }
1616
        return TCL_OK;
1617
    }
1618
 
1619
    /*
1620
     *  If a code fragment was specified, then save it in the
1621
     *  hash table for "usual" code.
1622
     */
1623
    else if (objc == 3) {
1624
        token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1625
        entry = Tcl_CreateHashEntry(&mergeInfo->usualCode, token, &newEntry);
1626
        if (!newEntry) {
1627
            codePtr = (Tcl_Obj*)Tcl_GetHashValue(entry);
1628
            Tcl_DecrRefCount(codePtr);
1629
        }
1630
 
1631
        codePtr = objv[2];
1632
        Tcl_IncrRefCount(codePtr);
1633
        Tcl_SetHashValue(entry, (ClientData)codePtr);
1634
 
1635
        return TCL_OK;
1636
    }
1637
 
1638
    /*
1639
     *  Otherwise, look for a code fragment with the specified tag.
1640
     */
1641
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1642
    entry = Tcl_FindHashEntry(&mergeInfo->usualCode, token);
1643
    if (entry) {
1644
        codePtr = (Tcl_Obj*)Tcl_GetHashValue(entry);
1645
        Tcl_SetObjResult(interp, codePtr);
1646
    }
1647
    return TCL_OK;
1648
}
1649
 
1650
 
1651
/*
1652
 * ------------------------------------------------------------------------
1653
 *  Itk_ArchInitCmd()
1654
 *
1655
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_initialize
1656
 *  method.  This method should be called out in the constructor for
1657
 *  each mega-widget class, to build the composite option list at
1658
 *  each class level.  Handles the following syntax:
1659
 *
1660
 *      itk_initialize ?-option val -option val...?
1661
 *
1662
 *  Integrates any class-based options into the composite option list,
1663
 *  handles option settings from the command line, and then configures
1664
 *  all options to have the proper initial value.
1665
 *
1666
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1667
 * ------------------------------------------------------------------------
1668
 */
1669
/* ARGSUSED */
1670
static int
1671
Itk_ArchInitCmd(dummy, interp, objc, objv)
1672
    ClientData dummy;        /* unused */
1673
    Tcl_Interp *interp;      /* current interpreter */
1674
    int objc;                /* number of arguments */
1675
    Tcl_Obj *CONST objv[];   /* argument objects */
1676
{
1677
    ItclClass *contextClass, *cdefn;
1678
    ItclObject *contextObj;
1679
    ArchInfo *info;
1680
 
1681
    int i, result;
1682
    char *token, *val;
1683
    Tcl_CallFrame *framePtr;
1684
    ItkClassOption *opt;
1685
    ItkClassOptTable *optTable;
1686
    Itcl_ListElem *part;
1687
    ArchOption *archOpt;
1688
    ArchOptionPart *optPart;
1689
    ItclHierIter hier;
1690
    ItclVarDefn *vdefn;
1691
    Tcl_HashSearch place;
1692
    Tcl_HashEntry *entry;
1693
 
1694
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
1695
        !contextObj) {
1696
 
1697
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1698
        Tcl_ResetResult(interp);
1699
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1700
            "improper usage: should be \"object ",
1701
            token, " ?-option value -option value...?\"",
1702
            (char*)NULL);
1703
        return TCL_ERROR;
1704
    }
1705
 
1706
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
1707
        return TCL_ERROR;
1708
    }
1709
 
1710
    /*
1711
     *  See what class is being initialized by getting the namespace
1712
     *  for the calling context.
1713
     */
1714
    framePtr = _Tcl_GetCallFrame(interp, 1);
1715
    if (framePtr && Itcl_IsClassNamespace(framePtr->nsPtr)) {
1716
        contextClass = (ItclClass*)framePtr->nsPtr->clientData;
1717
    }
1718
 
1719
    /*
1720
     *  Integrate all public variables for the current class
1721
     *  context into the composite option list.
1722
     */
1723
    Itcl_InitHierIter(&hier, contextClass);
1724
    while ((cdefn=Itcl_AdvanceHierIter(&hier)) != NULL) {
1725
        entry = Tcl_FirstHashEntry(&cdefn->variables, &place);
1726
        while (entry) {
1727
            vdefn = (ItclVarDefn*)Tcl_GetHashValue(entry);
1728
 
1729
            if (vdefn->member->protection == ITCL_PUBLIC) {
1730
                optPart = Itk_FindArchOptionPart(info,
1731
                    vdefn->member->name, (ClientData)vdefn);
1732
 
1733
                if (!optPart) {
1734
                    optPart = Itk_CreateOptionPart(interp, (ClientData)vdefn,
1735
                        Itk_PropagatePublicVar, (Tcl_CmdDeleteProc*)NULL,
1736
                        (ClientData)vdefn);
1737
 
1738
                    val = Itcl_GetInstanceVar(interp, vdefn->member->fullname,
1739
                        contextObj, contextObj->classDefn);
1740
 
1741
                    result = Itk_AddOptionPart(interp, info,
1742
                        vdefn->member->name, (char*)NULL, (char*)NULL,
1743
                        val, (char*)NULL, optPart, &archOpt);
1744
 
1745
                    if (result != TCL_OK) {
1746
                        Itk_DelOptionPart(optPart);
1747
                        return TCL_ERROR;
1748
                    }
1749
                }
1750
            }
1751
            entry = Tcl_NextHashEntry(&place);
1752
        }
1753
    }
1754
    Itcl_DeleteHierIter(&hier);
1755
 
1756
    /*
1757
     *  Integrate all class-based options for the current class
1758
     *  context into the composite option list.
1759
     */
1760
    optTable = Itk_FindClassOptTable(contextClass);
1761
    if (optTable) {
1762
        for (i=0; i < optTable->order.len; i++) {
1763
            opt = (ItkClassOption*)Tcl_GetHashValue(optTable->order.list[i]);
1764
 
1765
            optPart = Itk_FindArchOptionPart(info, opt->member->name,
1766
                (ClientData)contextClass);
1767
 
1768
            if (!optPart) {
1769
                optPart = Itk_CreateOptionPart(interp, (ClientData)opt,
1770
                    Itk_ConfigClassOption, (Tcl_CmdDeleteProc*)NULL,
1771
                    (ClientData)contextClass);
1772
 
1773
                result = Itk_AddOptionPart(interp, info,
1774
                    opt->member->name, opt->resName, opt->resClass,
1775
                    opt->init, (char*)NULL, optPart, &archOpt);
1776
 
1777
                if (result != TCL_OK) {
1778
                    Itk_DelOptionPart(optPart);
1779
                    return TCL_ERROR;
1780
                }
1781
            }
1782
        }
1783
    }
1784
 
1785
    /*
1786
     *  If any option values were specified on the command line,
1787
     *  override the current option settings.
1788
     */
1789
    if (objc > 1) {
1790
        for (objc--,objv++; objc > 0; objc-=2, objv+=2) {
1791
            token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1792
            if (objc < 2) {
1793
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1794
                    "value for \"", token, "\" missing",
1795
                    (char*)NULL);
1796
                return TCL_ERROR;
1797
            }
1798
 
1799
            val = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1800
            if (Itk_ArchConfigOption(interp, info, token, val) != TCL_OK) {
1801
                return TCL_ERROR;
1802
            }
1803
        }
1804
    }
1805
 
1806
    /*
1807
     *  If this is most-specific class, then finish constructing
1808
     *  the mega-widget:
1809
     *
1810
     *  Scan through all options in the composite list and
1811
     *  look for any that have been set but not initialized.
1812
     *  Invoke the parts of uninitialized options to propagate
1813
     *  changes and update the widget.
1814
     */
1815
    if (contextObj->classDefn == contextClass) {
1816
        for (i=0; i < info->order.len; i++) {
1817
            archOpt = (ArchOption*)Tcl_GetHashValue(info->order.list[i]);
1818
 
1819
            if ((archOpt->flags & ITK_ARCHOPT_INIT) == 0) {
1820
                val = Tcl_GetVar2(interp, "itk_option", archOpt->switchName, 0);
1821
 
1822
                if (!val) {
1823
                    Itk_ArchOptAccessError(interp, info, archOpt);
1824
                    return TCL_ERROR;
1825
                }
1826
 
1827
                part = Itcl_FirstListElem(&archOpt->parts);
1828
                while (part) {
1829
                    optPart = (ArchOptionPart*)Itcl_GetListValue(part);
1830
                    result  = (*optPart->configProc)(interp, contextObj,
1831
                        optPart->clientData, val);
1832
 
1833
                    if (result != TCL_OK) {
1834
                        Itk_ArchOptConfigError(interp, info, archOpt);
1835
                        return result;
1836
                    }
1837
                    part = Itcl_NextListElem(part);
1838
                }
1839
                archOpt->flags |= ITK_ARCHOPT_INIT;
1840
            }
1841
        }
1842
    }
1843
 
1844
    Tcl_ResetResult(interp);
1845
    return TCL_OK;
1846
}
1847
 
1848
 
1849
/*
1850
 * ------------------------------------------------------------------------
1851
 *  Itk_ArchOptionCmd()
1852
 *
1853
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_option
1854
 *  method.  Handles the following options:
1855
 *
1856
 *      itk_option define <switch> <resName> <resClass> <init> ?<config>?
1857
 *      itk_option add <name> ?<name>...?
1858
 *      itk_option remove <name> ?<name>...?
1859
 *
1860
 *  These commands customize the options list of a specific widget.
1861
 *  They are similar to the "itk_option" ensemble in the class definition
1862
 *  parser, but manipulate a single instance instead of an entire class.
1863
 *
1864
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1865
 * ------------------------------------------------------------------------
1866
 */
1867
/* ARGSUSED */
1868
static int
1869
Itk_ArchOptionCmd(dummy, interp, objc, objv)
1870
    ClientData dummy;        /* unused */
1871
    Tcl_Interp *interp;      /* current interpreter */
1872
    int objc;                /* number of arguments */
1873
    Tcl_Obj *CONST objv[];   /* argument objects */
1874
{
1875
    char *cmd, *token, c;
1876
    int length;
1877
 
1878
    /*
1879
     *  Check arguments and handle the various options...
1880
     */
1881
    if (objc < 2) {
1882
        cmd = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1883
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1884
            "wrong # args: should be one of...\n",
1885
            "  ", cmd, " add name ?name name...?\n",
1886
            "  ", cmd, " define -switch resourceName resourceClass init ?config?\n",
1887
            "  ", cmd, " remove name ?name name...?",
1888
            (char*)NULL);
1889
        return TCL_ERROR;
1890
    }
1891
 
1892
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
1893
    c = *token;
1894
    length = strlen(token);
1895
 
1896
    /*
1897
     *  Handle:  itk_option add...
1898
     */
1899
    if (c == 'a' && strncmp(token, "add", length) == 0) {
1900
        if (objc < 3) {
1901
            Tcl_WrongNumArgs(interp, 1, objv, "add name ?name name...?");
1902
            return TCL_ERROR;
1903
        }
1904
        return Itk_ArchOptionAddCmd(dummy, interp, objc-1, objv+1);
1905
    }
1906
 
1907
    /*
1908
     *  Handle:  itk_option remove...
1909
     */
1910
    else if (c == 'r' && strncmp(token, "remove", length) == 0) {
1911
        if (objc < 3) {
1912
            Tcl_WrongNumArgs(interp, 1, objv, "remove name ?name name...?");
1913
            return TCL_ERROR;
1914
        }
1915
        return Itk_ArchOptionRemoveCmd(dummy, interp, objc-1, objv+1);
1916
    }
1917
 
1918
    /*
1919
     *  Handle:  itk_option define...
1920
     */
1921
    else if (c == 'd' && strncmp(token, "define", length) == 0) {
1922
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1923
            "can only ", token, " options at the class level\n",
1924
            "(move this command into the class definition)",
1925
            (char*)NULL);
1926
        return TCL_ERROR;
1927
    }
1928
 
1929
    /*
1930
     *  Flag any errors.
1931
     */
1932
    cmd = Tcl_GetStringFromObj(objv[0], (int*)NULL);
1933
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1934
        "bad option \"", token,
1935
        "\": should be one of...\n",
1936
        "  ", cmd, " add name ?name name...?\n",
1937
        "  ", cmd, " define -switch resourceName resourceClass init ?config?\n",
1938
        "  ", cmd, " remove name ?name name...?",
1939
        (char*)NULL);
1940
    return TCL_ERROR;
1941
}
1942
 
1943
 
1944
/*
1945
 * ------------------------------------------------------------------------
1946
 *  Itk_ArchOptionAddCmd()
1947
 *
1948
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_option add
1949
 *  method.  Finds an option within a class definition or belonging to
1950
 *  a component widget and adds it into the option list for this widget.
1951
 *  If the option is already on the list, this method does nothing.
1952
 *  Handles the following syntax:
1953
 *
1954
 *      itk_option add <name> ?<name> <name>...?
1955
 *
1956
 *      where <name> is one of:
1957
 *        class::option
1958
 *        component.option
1959
 *
1960
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
1961
 * ------------------------------------------------------------------------
1962
 */
1963
/* ARGSUSED */
1964
static int
1965
Itk_ArchOptionAddCmd(dummy, interp, objc, objv)
1966
    ClientData dummy;        /* unused */
1967
    Tcl_Interp *interp;      /* current interpreter */
1968
    int objc;                /* number of arguments */
1969
    Tcl_Obj *CONST objv[];   /* argument objects */
1970
{
1971
    ItclClass *contextClass, *cdefn;
1972
    ItclObject *contextObj;
1973
    ArchInfo *info;
1974
 
1975
    int i, result;
1976
    char *token, *head, *tail, *sep, tmp;
1977
    ItkClassOption *opt;
1978
    GenericConfigOpt *generic;
1979
    ArchOption *archOpt;
1980
    ArchOptionPart *optPart;
1981
    ArchComponent *archComp;
1982
    ConfigCmdline *cmdlinePtr;
1983
    Tcl_HashEntry *entry;
1984
    Tcl_DString buffer;
1985
 
1986
    /*
1987
     *  Get the Archetype info associated with this widget.
1988
     */
1989
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
1990
        !contextObj) {
1991
 
1992
        Tcl_ResetResult(interp);
1993
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1994
            "cannot access options without an object context",
1995
            (char*)NULL);
1996
        return TCL_ERROR;
1997
    }
1998
 
1999
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
2000
        return TCL_ERROR;
2001
    }
2002
 
2003
    /*
2004
     *  Scan through the list of options and locate each one.
2005
     *  If it is not already on the option part list, add it.
2006
     */
2007
    for (i=1; i < objc; i++) {
2008
        token = Tcl_GetStringFromObj(objv[i], (int*)NULL);
2009
        Itcl_ParseNamespPath(token, &buffer, &head, &tail);
2010
 
2011
        /*
2012
         *  HANDLE:  class::option
2013
         */
2014
        if (head) {
2015
            cdefn = Itcl_FindClass(interp, head, /* autoload */ 1);
2016
            if (!cdefn) {
2017
                Tcl_DStringFree(&buffer);
2018
                return TCL_ERROR;
2019
            }
2020
 
2021
            opt = Itk_FindClassOption(cdefn, tail);
2022
            if (!opt) {
2023
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2024
                    "option \"", tail, "\" not defined in class \"",
2025
                    cdefn->fullname, "\"",
2026
                    (char*)NULL);
2027
                Tcl_DStringFree(&buffer);
2028
                return TCL_ERROR;
2029
            }
2030
 
2031
            optPart = Itk_FindArchOptionPart(info, opt->member->name,
2032
                (ClientData)cdefn);
2033
 
2034
            if (!optPart) {
2035
                optPart = Itk_CreateOptionPart(interp, (ClientData)opt,
2036
                    Itk_ConfigClassOption, (Tcl_CmdDeleteProc*)NULL,
2037
                    (ClientData)cdefn);
2038
 
2039
                result = Itk_AddOptionPart(interp, info, opt->member->name,
2040
                    opt->resName, opt->resClass, opt->init, (char*)NULL,
2041
                    optPart, &archOpt);
2042
 
2043
                if (result != TCL_OK) {
2044
                    Itk_DelOptionPart(optPart);
2045
                    Tcl_DStringFree(&buffer);
2046
                    return TCL_ERROR;
2047
                }
2048
            }
2049
            Tcl_DStringFree(&buffer);
2050
            continue;
2051
        }
2052
 
2053
        Tcl_DStringFree(&buffer);
2054
 
2055
        /*
2056
         *  HANDLE:  component.option
2057
         */
2058
        sep = strstr(token, ".");
2059
        if (sep) {
2060
            tmp = *sep;
2061
            *sep = '\0';
2062
            head = token;
2063
            tail = sep+1;
2064
 
2065
            entry = Tcl_FindHashEntry(&info->components, head);
2066
            if (!entry) {
2067
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2068
                    "name \"", head, "\" is not a component",
2069
                    (char*)NULL);
2070
                *sep = tmp;
2071
                return TCL_ERROR;
2072
            }
2073
            *sep = tmp;
2074
            archComp = (ArchComponent*)Tcl_GetHashValue(entry);
2075
 
2076
            generic = Itk_CreateGenericOpt(interp, tail, archComp->accessCmd);
2077
            if (!generic) {
2078
                char msg[256];
2079
                sprintf(msg, "\n    (while adding option \"%.100s\")", token);
2080
                Tcl_AddErrorInfo(interp, msg);
2081
                return TCL_ERROR;
2082
            }
2083
 
2084
            optPart = Itk_FindArchOptionPart(info, generic->switchName,
2085
                (ClientData)archComp);
2086
 
2087
            if (!optPart) {
2088
                cmdlinePtr = Itk_CreateConfigCmdline(interp,
2089
                    archComp->accessCmd, generic->switchName);
2090
 
2091
                optPart = Itk_CreateOptionPart(interp, (ClientData)cmdlinePtr,
2092
                    Itk_PropagateOption, Itk_DeleteConfigCmdline,
2093
                    (ClientData)archComp);
2094
 
2095
                result = Itk_AddOptionPart(interp, info,
2096
                    generic->switchName, generic->resName, generic->resClass,
2097
                    generic->init, generic->value, optPart, &archOpt);
2098
 
2099
                if (result != TCL_OK) {
2100
                    Itk_DelOptionPart(optPart);
2101
                    Itk_DelGenericOpt(generic);
2102
                    return TCL_ERROR;
2103
                }
2104
            }
2105
            Itk_DelGenericOpt(generic);
2106
            continue;
2107
        }
2108
 
2109
        /*
2110
         *  Anything else is an error.
2111
         */
2112
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2113
            "bad option \"", token, "\": should be one of...\n",
2114
            "  class::option\n",
2115
            "  component.option",
2116
            (char*)NULL);
2117
        return TCL_ERROR;
2118
    }
2119
 
2120
    return TCL_OK;
2121
}
2122
 
2123
 
2124
/*
2125
 * ------------------------------------------------------------------------
2126
 *  Itk_ArchOptionRemoveCmd()
2127
 *
2128
 *  Invoked by [incr Tcl] to handle the itk::Archetype::itk_option remove
2129
 *  method.  Finds an option within a class definition or belonging to
2130
 *  a component widget and removes it from the option list for this widget.
2131
 *  If the option has already been removed from the list, this method does
2132
 *  nothing.  Handles the following syntax:
2133
 *
2134
 *      itk_option remove <name> ?<name> <name>...?
2135
 *
2136
 *      where <name> is one of:
2137
 *        class::option
2138
 *        component.option
2139
 *
2140
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
2141
 * ------------------------------------------------------------------------
2142
 */
2143
/* ARGSUSED */
2144
static int
2145
Itk_ArchOptionRemoveCmd(dummy, interp, objc, objv)
2146
    ClientData dummy;        /* unused */
2147
    Tcl_Interp *interp;      /* current interpreter */
2148
    int objc;                /* number of arguments */
2149
    Tcl_Obj *CONST objv[];   /* argument objects */
2150
{
2151
    ItclClass *contextClass, *cdefn;
2152
    ItclObject *contextObj;
2153
    ArchInfo *info;
2154
 
2155
    int i;
2156
    char *name, *head, *tail, *sep, tmp;
2157
    ItkClassOption *opt;
2158
    GenericConfigOpt *generic;
2159
    ArchComponent *archComp;
2160
    Tcl_HashEntry *entry;
2161
    Tcl_DString buffer;
2162
 
2163
    /*
2164
     *  Get the Archetype info associated with this widget.
2165
     */
2166
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
2167
        !contextObj) {
2168
 
2169
        Tcl_ResetResult(interp);
2170
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2171
            "cannot access options without an object context",
2172
            (char*)NULL);
2173
        return TCL_ERROR;
2174
    }
2175
 
2176
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
2177
        return TCL_ERROR;
2178
    }
2179
 
2180
    /*
2181
     *  Scan through the list of options and locate each one.
2182
     *  If it is on the option list, remove it.
2183
     */
2184
    for (i=1; i < objc; i++) {
2185
        name = Tcl_GetStringFromObj(objv[i], (int*)NULL);
2186
        Itcl_ParseNamespPath(name, &buffer, &head, &tail);
2187
 
2188
        /*
2189
         *  HANDLE:  class::option
2190
         */
2191
        if (head) {
2192
            cdefn = Itcl_FindClass(interp, head, /* autoload */ 1);
2193
            if (!cdefn) {
2194
                Tcl_DStringFree(&buffer);
2195
                return TCL_ERROR;
2196
            }
2197
 
2198
            opt = Itk_FindClassOption(cdefn, tail);
2199
            if (!opt) {
2200
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2201
                    "option \"", tail, "\" not defined in class \"",
2202
                    cdefn->fullname, "\"",
2203
                    (char*)NULL);
2204
                Tcl_DStringFree(&buffer);
2205
                return TCL_ERROR;
2206
            }
2207
 
2208
            Itk_RemoveArchOptionPart(info, opt->member->name,
2209
                (ClientData)cdefn);
2210
 
2211
            Tcl_DStringFree(&buffer);
2212
            continue;
2213
        }
2214
        Tcl_DStringFree(&buffer);
2215
 
2216
        /*
2217
         *  HANDLE:  component.option
2218
         */
2219
        sep = strstr(name, ".");
2220
        if (sep) {
2221
            tmp = *sep;
2222
            *sep = '\0';
2223
            head = name;
2224
            tail = sep+1;
2225
 
2226
            entry = Tcl_FindHashEntry(&info->components, head);
2227
            if (!entry) {
2228
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2229
                    "name \"", head, "\" is not a component",
2230
                    (char*)NULL);
2231
                *sep = tmp;
2232
                return TCL_ERROR;
2233
            }
2234
            *sep = tmp;
2235
            archComp = (ArchComponent*)Tcl_GetHashValue(entry);
2236
 
2237
            generic = Itk_CreateGenericOpt(interp, tail, archComp->accessCmd);
2238
            if (!generic) {
2239
                char msg[256];
2240
                sprintf(msg, "\n    (while removing option \"%.100s\")",
2241
                    name);
2242
                Tcl_AddErrorInfo(interp, msg);
2243
                return TCL_ERROR;
2244
            }
2245
 
2246
            Itk_RemoveArchOptionPart(info, generic->switchName,
2247
                (ClientData)archComp);
2248
 
2249
            Itk_DelGenericOpt(generic);
2250
            continue;
2251
        }
2252
 
2253
        /*
2254
         *  Anything else is an error.
2255
         */
2256
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2257
            "bad option \"", name, "\": should be one of...\n",
2258
            "  class::option\n",
2259
            "  component.option",
2260
            (char*)NULL);
2261
        return TCL_ERROR;
2262
    }
2263
 
2264
    return TCL_OK;
2265
}
2266
 
2267
 
2268
/*
2269
 * ------------------------------------------------------------------------
2270
 *  Itk_ArchCompAccessCmd()
2271
 *
2272
 *  Invoked by [incr Tcl] to handle the itk::Archetype::component method.
2273
 *  Finds the requested component and invokes the <command> as a method
2274
 *  on that component.
2275
 *
2276
 *  Handles the following syntax:
2277
 *
2278
 *      component
2279
 *      component <name>
2280
 *      component <name> <command> ?<arg> <arg>...?
2281
 *
2282
 *  With no arguments, this command returns the names of components
2283
 *  that can be accessed from the current context.  Note that components
2284
 *  respect public/protected/private declarations, so private and
2285
 *  protected components may not be accessible from all namespaces.
2286
 *
2287
 *  If a component name is specified, then this command returns the
2288
 *  window name for that component.
2289
 *
2290
 *  If a series of arguments follow the component name, they are treated
2291
 *  as a method invocation, and dispatched to the component.
2292
 *
2293
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
2294
 * ------------------------------------------------------------------------
2295
 */
2296
/* ARGSUSED */
2297
static int
2298
Itk_ArchCompAccessCmd(dummy, interp, objc, objv)
2299
    ClientData dummy;        /* unused */
2300
    Tcl_Interp *interp;      /* current interpreter */
2301
    int objc;                /* number of arguments */
2302
    Tcl_Obj *CONST objv[];   /* argument objects */
2303
{
2304
    int i, result;
2305
    char *token, *name, *val;
2306
    Tcl_Namespace *callingNs;
2307
    ItclClass *contextClass;
2308
    ItclObject *contextObj;
2309
    Tcl_CallFrame *framePtr;
2310
    Tcl_HashEntry *entry;
2311
    Tcl_HashSearch place;
2312
    ArchInfo *info;
2313
    ArchComponent *archComp;
2314
    int cmdlinec;
2315
    Tcl_Obj *objPtr, *cmdlinePtr, **cmdlinev;
2316
 
2317
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
2318
        !contextObj) {
2319
 
2320
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
2321
        Tcl_ResetResult(interp);
2322
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2323
            "improper usage: should be \"object ",
2324
            token, " ?name option arg arg...?\"",
2325
            (char*)NULL);
2326
        return TCL_ERROR;
2327
    }
2328
 
2329
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
2330
        return TCL_ERROR;
2331
    }
2332
 
2333
    framePtr = _Tcl_GetCallFrame(interp, 1);
2334
    if (framePtr) {
2335
        callingNs = framePtr->nsPtr;
2336
    } else {
2337
        callingNs = Tcl_GetGlobalNamespace(interp);
2338
    }
2339
 
2340
    /*
2341
     *  With no arguments, return a list of components that can be
2342
     *  accessed from the calling scope.
2343
     */
2344
    if (objc == 1) {
2345
        entry = Tcl_FirstHashEntry(&info->components, &place);
2346
        while (entry) {
2347
            archComp = (ArchComponent*)Tcl_GetHashValue(entry);
2348
            if (Itcl_CanAccess(archComp->member, callingNs)) {
2349
                name = Tcl_GetHashKey(&info->components, entry);
2350
                Tcl_AppendElement(interp, name);
2351
            }
2352
            entry = Tcl_NextHashEntry(&place);
2353
        }
2354
        return TCL_OK;
2355
    }
2356
 
2357
    /*
2358
     *  Make sure the requested component exists.
2359
     */
2360
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
2361
    entry = Tcl_FindHashEntry(&info->components, token);
2362
    if (entry) {
2363
        archComp = (ArchComponent*)Tcl_GetHashValue(entry);
2364
    } else {
2365
        archComp = NULL;
2366
    }
2367
 
2368
    if (archComp == NULL) {
2369
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2370
            "name \"", token, "\" is not a component",
2371
            (char*)NULL);
2372
        return TCL_ERROR;
2373
    }
2374
 
2375
    if (!Itcl_CanAccess(archComp->member, callingNs)) {
2376
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2377
            "can't access component \"", token, "\" from context \"",
2378
            callingNs->fullName, "\"",
2379
            (char*)NULL);
2380
        return TCL_ERROR;
2381
    }
2382
 
2383
    /*
2384
     *  If only the component name is specified, then return the
2385
     *  window name for this component.
2386
     */
2387
    if (objc == 2) {
2388
        val = Tcl_GetVar2(interp, "itk_component", token, 0);
2389
        if (!val) {
2390
            Tcl_ResetResult(interp);
2391
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2392
                "internal error: cannot access itk_component(", token, ")",
2393
                (char*)NULL);
2394
 
2395
            if (contextObj->accessCmd) {
2396
                Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
2397
                Tcl_AppendToObj(resultPtr, " in widget \"", -1);
2398
                Tcl_GetCommandFullName(contextObj->classDefn->interp,
2399
                    contextObj->accessCmd, resultPtr);
2400
                Tcl_AppendToObj(resultPtr, "\"", -1);
2401
            }
2402
            return TCL_ERROR;
2403
        }
2404
        Tcl_SetResult(interp, val, TCL_VOLATILE);
2405
        return TCL_OK;
2406
    }
2407
 
2408
    /*
2409
     *  Otherwise, treat the rest of the command line as a method
2410
     *  invocation on the requested component.  Invoke the remaining
2411
     *  command-line arguments as a method for that component.
2412
     */
2413
    cmdlinePtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
2414
    Tcl_IncrRefCount(cmdlinePtr);
2415
 
2416
    objPtr = Tcl_NewStringObj((char*)NULL, 0);
2417
    Tcl_GetCommandFullName(interp, archComp->accessCmd, objPtr);
2418
    Tcl_ListObjAppendElement((Tcl_Interp*)NULL, cmdlinePtr, objPtr);
2419
 
2420
    for (i=2; i < objc; i++) {
2421
        Tcl_ListObjAppendElement((Tcl_Interp*)NULL, cmdlinePtr, objv[i]);
2422
    }
2423
 
2424
    (void) Tcl_ListObjGetElements((Tcl_Interp*)NULL, cmdlinePtr,
2425
        &cmdlinec, &cmdlinev);
2426
 
2427
    result = Itcl_EvalArgs(interp, cmdlinec, cmdlinev);
2428
 
2429
    Tcl_DecrRefCount(cmdlinePtr);
2430
 
2431
    return result;
2432
}
2433
 
2434
 
2435
/*
2436
 * ------------------------------------------------------------------------
2437
 *  Itk_ArchConfigureCmd()
2438
 *
2439
 *  Invoked by [incr Tcl] to handle the itk::Archetype::configure method.
2440
 *  Mimics the usual Tk "configure" method for Archetype mega-widgets.
2441
 *
2442
 *      configure
2443
 *      configure -name
2444
 *      configure -name value ?-name value ...?
2445
 *
2446
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
2447
 * ------------------------------------------------------------------------
2448
 */
2449
/* ARGSUSED */
2450
static int
2451
Itk_ArchConfigureCmd(dummy, interp, objc, objv)
2452
    ClientData dummy;        /* unused */
2453
    Tcl_Interp *interp;      /* current interpreter */
2454
    int objc;                /* number of arguments */
2455
    Tcl_Obj *CONST objv[];   /* argument objects */
2456
{
2457
    int i;
2458
    char *token, *val;
2459
    ItclClass *contextClass;
2460
    ItclObject *contextObj;
2461
    ArchInfo *info;
2462
    Tcl_HashEntry *entry;
2463
    ArchOption *archOpt;
2464
    Tcl_DString buffer;
2465
 
2466
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
2467
        !contextObj) {
2468
 
2469
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
2470
        Tcl_ResetResult(interp);
2471
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2472
            "improper usage: should be \"object ",
2473
            token, " ?-option? ?value -option value...?\"",
2474
            (char*)NULL);
2475
        return TCL_ERROR;
2476
    }
2477
 
2478
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
2479
        return TCL_ERROR;
2480
    }
2481
 
2482
    /*
2483
     *  If there are no extra arguments, then return a list of all
2484
     *  known configuration options.  Each option has the form:
2485
     *    {name resName resClass init value}
2486
     */
2487
    if (objc == 1) {
2488
        Tcl_DStringInit(&buffer);
2489
 
2490
        for (i=0; i < info->order.len; i++) {
2491
            archOpt = (ArchOption*)Tcl_GetHashValue(info->order.list[i]);
2492
            val = Tcl_GetVar2(interp, "itk_option", archOpt->switchName, 0);
2493
            if (!val) {
2494
                Itk_ArchOptAccessError(interp, info, archOpt);
2495
                Tcl_DStringFree(&buffer);
2496
                return TCL_ERROR;
2497
            }
2498
 
2499
            Tcl_DStringStartSublist(&buffer);
2500
            Tcl_DStringAppendElement(&buffer, archOpt->switchName);
2501
            Tcl_DStringAppendElement(&buffer,
2502
                (archOpt->resName) ? archOpt->resName : "");
2503
            Tcl_DStringAppendElement(&buffer,
2504
                (archOpt->resClass) ? archOpt->resClass : "");
2505
            Tcl_DStringAppendElement(&buffer,
2506
                (archOpt->init) ? archOpt->init : "");
2507
            Tcl_DStringAppendElement(&buffer, val);
2508
            Tcl_DStringEndSublist(&buffer);
2509
        }
2510
        Tcl_DStringResult(interp, &buffer);
2511
        Tcl_DStringFree(&buffer);
2512
        return TCL_OK;
2513
    }
2514
 
2515
    /*
2516
     *  If there is just one argument, then query the information
2517
     *  for that one argument and return:
2518
     *    {name resName resClass init value}
2519
     */
2520
    else if (objc == 2) {
2521
        token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
2522
        entry = Tcl_FindHashEntry(&info->options, token);
2523
        if (!entry) {
2524
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2525
                "unknown option \"", token, "\"",
2526
                (char*)NULL);
2527
            return TCL_ERROR;
2528
        }
2529
 
2530
        archOpt = (ArchOption*)Tcl_GetHashValue(entry);
2531
        val = Tcl_GetVar2(interp, "itk_option", archOpt->switchName, 0);
2532
        if (!val) {
2533
            Itk_ArchOptAccessError(interp, info, archOpt);
2534
            return TCL_ERROR;
2535
        }
2536
 
2537
        Tcl_AppendElement(interp, archOpt->switchName);
2538
        Tcl_AppendElement(interp,
2539
            (archOpt->resName) ? archOpt->resName : "");
2540
        Tcl_AppendElement(interp,
2541
            (archOpt->resClass) ? archOpt->resClass : "");
2542
        Tcl_AppendElement(interp,
2543
            (archOpt->init) ? archOpt->init : "");
2544
        Tcl_AppendElement(interp, val);
2545
 
2546
        return TCL_OK;
2547
    }
2548
 
2549
    /*
2550
     *  Otherwise, it must be a series of "-option value" assignments.
2551
     *  Look up each option and assign the new value.
2552
     */
2553
    for (objc--,objv++; objc > 0; objc-=2, objv+=2) {
2554
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
2555
        if (objc < 2) {
2556
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2557
                "value for \"", token, "\" missing",
2558
                (char*)NULL);
2559
            return TCL_ERROR;
2560
        }
2561
        val = Tcl_GetStringFromObj(objv[1], (int*)NULL);
2562
 
2563
        if (Itk_ArchConfigOption(interp, info, token, val) != TCL_OK) {
2564
            return TCL_ERROR;
2565
        }
2566
    }
2567
 
2568
    Tcl_ResetResult(interp);
2569
    return TCL_OK;
2570
}
2571
 
2572
 
2573
/*
2574
 * ------------------------------------------------------------------------
2575
 *  Itk_ArchCgetCmd()
2576
 *
2577
 *  Invoked by [incr Tcl] to handle the itk::Archetype::cget method.
2578
 *  Mimics the usual Tk "cget" method for Archetype mega-widgets.
2579
 *
2580
 *      cget -name
2581
 *
2582
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
2583
 * ------------------------------------------------------------------------
2584
 */
2585
/* ARGSUSED */
2586
static int
2587
Itk_ArchCgetCmd(dummy, interp, objc, objv)
2588
    ClientData dummy;        /* unused */
2589
    Tcl_Interp *interp;      /* current interpreter */
2590
    int objc;                /* number of arguments */
2591
    Tcl_Obj *CONST objv[];   /* argument objects */
2592
{
2593
    char *token, *val;
2594
    ItclClass *contextClass;
2595
    ItclObject *contextObj;
2596
    ArchInfo *info;
2597
    Tcl_HashEntry *entry;
2598
    ArchOption *archOpt;
2599
 
2600
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
2601
        !contextObj) {
2602
 
2603
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
2604
        Tcl_ResetResult(interp);
2605
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2606
            "improper usage: should be \"object ", token, " -option\"",
2607
            (char*)NULL);
2608
        return TCL_ERROR;
2609
    }
2610
 
2611
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
2612
        return TCL_ERROR;
2613
    }
2614
 
2615
    if (objc != 2) {
2616
        Tcl_WrongNumArgs(interp, 1, objv, "option");
2617
        return TCL_ERROR;
2618
    }
2619
 
2620
    /*
2621
     *  Look up the specified option and get its current value.
2622
     */
2623
    token = Tcl_GetStringFromObj(objv[1], (int*)NULL);
2624
    entry = Tcl_FindHashEntry(&info->options, token);
2625
    if (!entry) {
2626
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2627
            "unknown option \"", token, "\"",
2628
            (char*)NULL);
2629
        return TCL_ERROR;
2630
    }
2631
 
2632
    archOpt = (ArchOption*)Tcl_GetHashValue(entry);
2633
    val = Tcl_GetVar2(interp, "itk_option", archOpt->switchName, 0);
2634
    if (!val) {
2635
        Itk_ArchOptAccessError(interp, info, archOpt);
2636
        return TCL_ERROR;
2637
    }
2638
 
2639
    Tcl_SetResult(interp, val, TCL_VOLATILE);
2640
    return TCL_OK;
2641
}
2642
 
2643
 
2644
/*
2645
 * ------------------------------------------------------------------------
2646
 *  Itk_PropagateOption()
2647
 *
2648
 *  Invoked whenever a widget-based configuration option has been
2649
 *  configured with a new value.  Propagates the new value down to
2650
 *  the widget by invoking the "configure" method on the widget.
2651
 *  This causes the widget to bring itself up to date automatically.
2652
 *
2653
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
2654
 *  message in the interpreter) if anything goes wrong.
2655
 * ------------------------------------------------------------------------
2656
 */
2657
/* ARGSUSED */
2658
static int
2659
Itk_PropagateOption(interp, contextObj, cdata, newval)
2660
    Tcl_Interp *interp;        /* interpreter managing the class */
2661
    ItclObject *contextObj;    /* itcl object being configured */
2662
    ClientData cdata;          /* command prefix to use for configuration */
2663
    char *newval;              /* new value for this option */
2664
{
2665
    ConfigCmdline *cmdlinePtr = (ConfigCmdline*)cdata;
2666
    int result;
2667
    Tcl_Obj *objPtr;
2668
 
2669
    objPtr = Tcl_NewStringObj(newval, -1);
2670
    Tcl_IncrRefCount(objPtr);
2671
 
2672
    cmdlinePtr->objv[3] = objPtr;
2673
    result = Itcl_EvalArgs(interp, 4, cmdlinePtr->objv);
2674
 
2675
    Tcl_DecrRefCount(objPtr);
2676
    return result;
2677
}
2678
 
2679
 
2680
/*
2681
 * ------------------------------------------------------------------------
2682
 *  Itk_PropagatePublicVar()
2683
 *
2684
 *  Invoked whenever a mega-widget configuration option containing
2685
 *  a public variable part has been configured with a new value.
2686
 *  Updates the public variable with the new value and invokes any
2687
 *  "config" code associated with it.
2688
 *
2689
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
2690
 *  message in the interpreter) if anything goes wrong.
2691
 * ------------------------------------------------------------------------
2692
 */
2693
/* ARGSUSED */
2694
static int
2695
Itk_PropagatePublicVar(interp, contextObj, cdata, newval)
2696
    Tcl_Interp *interp;        /* interpreter managing the class */
2697
    ItclObject *contextObj;    /* itcl object being configured */
2698
    ClientData cdata;          /* command prefix to use for configuration */
2699
    char *newval;              /* new value for this option */
2700
{
2701
    ItclVarDefn *vdefn = (ItclVarDefn*)cdata;
2702
 
2703
    int result;
2704
    char *val;
2705
    ItclContext context;
2706
    ItclMemberCode *mcode;
2707
    Tcl_CallFrame *uplevelFramePtr, *oldFramePtr;
2708
 
2709
    /*
2710
     *  Update the public variable with the new option value.
2711
     *  There should already be a call frame installed for handling
2712
     *  instance variables, but make sure that the namespace context
2713
     *  is the most-specific class, so that the public variable can
2714
     *  be found.
2715
     */
2716
    result = Itcl_PushContext(interp, (ItclMember*)NULL,
2717
        contextObj->classDefn, contextObj, &context);
2718
 
2719
    if (result == TCL_OK) {
2720
        val = Tcl_SetVar2(interp, vdefn->member->fullname, (char*)NULL,
2721
            newval, TCL_LEAVE_ERR_MSG);
2722
 
2723
        if (!val) {
2724
            result = TCL_ERROR;
2725
        }
2726
        Itcl_PopContext(interp, &context);
2727
    }
2728
 
2729
    if (result != TCL_OK) {
2730
        char msg[256];
2731
        sprintf(msg, "\n    (error in configuration of public variable \"%.100s\")", vdefn->member->fullname);
2732
        Tcl_AddErrorInfo(interp, msg);
2733
        return TCL_ERROR;
2734
    }
2735
 
2736
    /*
2737
     *  If this variable has some "config" code, invoke it now.
2738
     *
2739
     *  NOTE:  Invoke the "config" code in the class scope
2740
     *    containing the data member.
2741
     */
2742
    mcode = vdefn->member->code;
2743
    if (mcode && mcode->procPtr->bodyPtr) {
2744
 
2745
        uplevelFramePtr = _Tcl_GetCallFrame(interp, 1);
2746
        oldFramePtr = _Tcl_ActivateCallFrame(interp, uplevelFramePtr);
2747
 
2748
        result = Itcl_EvalMemberCode(interp, (ItclMemberFunc*)NULL,
2749
            vdefn->member, contextObj, 0, (Tcl_Obj**)NULL);
2750
 
2751
        (void) _Tcl_ActivateCallFrame(interp, oldFramePtr);
2752
 
2753
        if (result == TCL_OK) {
2754
            Tcl_ResetResult(interp);
2755
        } else {
2756
            char msg[256];
2757
            sprintf(msg, "\n    (error in configuration of public variable \"%.100s\")", vdefn->member->fullname);
2758
            Tcl_AddErrorInfo(interp, msg);
2759
        }
2760
    }
2761
 
2762
    return result;
2763
}
2764
 
2765
 
2766
/*
2767
 * ------------------------------------------------------------------------
2768
 *  Itk_ArchSetOption()
2769
 *
2770
 *  Sets a configuration option within an Archetype mega-widget.
2771
 *  Changes the "itk_option" array to reflect the new value, but
2772
 *  unlike Itk_ArchConfigOption(), this procedure does not update
2773
 *  the widget by propagating changes or invoking any "config" code.
2774
 *  It merely sets the widget state.  It is useful when a widget is
2775
 *  first being constructed, to initialize option values.
2776
 *
2777
 *  NOTE:  This procedure assumes that there is a valid object context
2778
 *    and a call frame supporting object data member access.  It is
2779
 *    usually called from within the methods of the Archetype base
2780
 *    class, so this is a good assumption.  If it is called anywhere
2781
 *    else, the caller is responsible for installing the object context
2782
 *    and setting up a call frame.
2783
 *
2784
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
2785
 *  message in the interpreter) if anything goes wrong.
2786
 * ------------------------------------------------------------------------
2787
 */
2788
static int
2789
Itk_ArchSetOption(interp, info, name, value)
2790
    Tcl_Interp *interp;        /* interpreter managing this widget */
2791
    ArchInfo *info;            /* Archetype info */
2792
    char *name;                /* name of configuration option */
2793
    char *value;               /* new value for configuration option */
2794
{
2795
    Tcl_HashEntry *entry;
2796
    ArchOption *archOpt;
2797
 
2798
    entry = Tcl_FindHashEntry(&info->options, name);
2799
    if (!entry) {
2800
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2801
            "unknown option \"", name, "\"",
2802
            (char*)NULL);
2803
        return TCL_ERROR;
2804
    }
2805
    archOpt = (ArchOption*)Tcl_GetHashValue(entry);
2806
 
2807
    if (!Tcl_SetVar2(interp, "itk_option", archOpt->switchName, value, 0)) {
2808
        Itk_ArchOptAccessError(interp, info, archOpt);
2809
        return TCL_ERROR;
2810
    }
2811
    return TCL_OK;
2812
}
2813
 
2814
 
2815
/*
2816
 * ------------------------------------------------------------------------
2817
 *  Itk_ArchConfigOption()
2818
 *
2819
 *  Sets a configuration option within an Archetype mega-widget.
2820
 *  Changes the "itk_option" array to reflect the new value, and then
2821
 *  invokes any option parts to handle the new setting or propagate
2822
 *  the value down to component parts.
2823
 *
2824
 *  NOTE:  This procedure assumes that there is a valid object context
2825
 *    and a call frame supporting object data member access.  It is
2826
 *    usually called from within the methods of the Archetype base
2827
 *    class, so this is a good assumption.  If it is called anywhere
2828
 *    else, the caller is responsible for installing the object context
2829
 *    and setting up a call frame.
2830
 *
2831
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error
2832
 *  message in the interpreter) if anything goes wrong.
2833
 * ------------------------------------------------------------------------
2834
 */
2835
static int
2836
Itk_ArchConfigOption(interp, info, name, value)
2837
    Tcl_Interp *interp;        /* interpreter managing this widget */
2838
    ArchInfo *info;            /* Archetype info */
2839
    char *name;                /* name of configuration option */
2840
    char *value;               /* new value for configuration option */
2841
{
2842
    int result;
2843
    char *v, *lastval;
2844
    Tcl_HashEntry *entry;
2845
    ArchOption *archOpt;
2846
    Itcl_ListElem *part;
2847
    ArchOptionPart *optPart;
2848
    Itcl_InterpState istate;
2849
 
2850
    /*
2851
     *  Query the "itk_option" array to get the current setting.
2852
     */
2853
    entry = Tcl_FindHashEntry(&info->options, name);
2854
    if (!entry) {
2855
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2856
            "unknown option \"", name, "\"",
2857
            (char*)NULL);
2858
        return TCL_ERROR;
2859
    }
2860
    archOpt = (ArchOption*)Tcl_GetHashValue(entry);
2861
 
2862
    v = Tcl_GetVar2(interp, "itk_option", archOpt->switchName, 0);
2863
    if (v) {
2864
        lastval = (char*)ckalloc((unsigned)(strlen(v)+1));
2865
        strcpy(lastval, v);
2866
    } else {
2867
        lastval = NULL;
2868
    }
2869
 
2870
    /*
2871
     *  Update the "itk_option" array with the new setting.
2872
     */
2873
    if (!Tcl_SetVar2(interp, "itk_option", archOpt->switchName, value, 0)) {
2874
        Itk_ArchOptAccessError(interp, info, archOpt);
2875
        result = TCL_ERROR;
2876
        goto configDone;
2877
    }
2878
 
2879
    /*
2880
     *  Scan through all option parts to handle the new setting.
2881
     */
2882
    result = TCL_OK;
2883
    part   = Itcl_FirstListElem(&archOpt->parts);
2884
 
2885
    while (part) {
2886
        optPart = (ArchOptionPart*)Itcl_GetListValue(part);
2887
        result  = (*optPart->configProc)(interp, info->itclObj,
2888
            optPart->clientData, value);
2889
 
2890
        if (result != TCL_OK) {
2891
            Itk_ArchOptConfigError(interp, info, archOpt);
2892
            break;
2893
        }
2894
        part = Itcl_NextListElem(part);
2895
    }
2896
 
2897
    /*
2898
     *  If the option configuration failed, then set the option
2899
     *  back to its previous settings.  Scan back through all of
2900
     *  the option parts and sync them up with the old value.
2901
     */
2902
    if (result == TCL_ERROR) {
2903
        istate = Itcl_SaveInterpState(interp, result);
2904
 
2905
        Tcl_SetVar2(interp, "itk_option", archOpt->switchName, lastval, 0);
2906
 
2907
        part = Itcl_FirstListElem(&archOpt->parts);
2908
        while (part) {
2909
            optPart = (ArchOptionPart*)Itcl_GetListValue(part);
2910
            (*optPart->configProc)(interp, info->itclObj,
2911
                optPart->clientData, lastval);
2912
 
2913
            part = Itcl_NextListElem(part);
2914
        }
2915
        result = Itcl_RestoreInterpState(interp, istate);
2916
    }
2917
 
2918
    archOpt->flags |= ITK_ARCHOPT_INIT;  /* option has been set */
2919
 
2920
configDone:
2921
    if (lastval) {
2922
        ckfree(lastval);
2923
    }
2924
    return result;
2925
}
2926
 
2927
 
2928
/*
2929
 * ------------------------------------------------------------------------
2930
 *  Itk_ArchOptConfigError()
2931
 *
2932
 *  Simply utility which adds error information after a option
2933
 *  configuration fails.  Adds traceback information to the given
2934
 *  interpreter.
2935
 * ------------------------------------------------------------------------
2936
 */
2937
static void
2938
Itk_ArchOptConfigError(interp, info, archOpt)
2939
    Tcl_Interp *interp;            /* interpreter handling this object */
2940
    ArchInfo *info;                /* info associated with mega-widget */
2941
    ArchOption *archOpt;           /* configuration option that failed */
2942
{
2943
    Tcl_Obj *objPtr;
2944
 
2945
    objPtr = Tcl_NewStringObj((char*)NULL, 0);
2946
    Tcl_IncrRefCount(objPtr);
2947
 
2948
    Tcl_AppendToObj(objPtr, "\n    (while configuring option \"", -1);
2949
    Tcl_AppendToObj(objPtr, archOpt->switchName, -1);
2950
    Tcl_AppendToObj(objPtr, "\"", -1);
2951
 
2952
    if (info->itclObj && info->itclObj->accessCmd) {
2953
        Tcl_AppendToObj(objPtr, " for widget \"", -1);
2954
        Tcl_GetCommandFullName(interp, info->itclObj->accessCmd, objPtr);
2955
        Tcl_AppendToObj(objPtr, "\")", -1);
2956
    }
2957
    Tcl_AddErrorInfo(interp, Tcl_GetStringFromObj(objPtr, (int*)NULL));
2958
    Tcl_DecrRefCount(objPtr);
2959
}
2960
 
2961
 
2962
/*
2963
 * ------------------------------------------------------------------------
2964
 *  Itk_ArchOptAccessError()
2965
 *
2966
 *  Simply utility which adds error information after an option
2967
 *  value access fails.  Adds traceback information to the given
2968
 *  interpreter.
2969
 * ------------------------------------------------------------------------
2970
 */
2971
static void
2972
Itk_ArchOptAccessError(interp, info, archOpt)
2973
    Tcl_Interp *interp;            /* interpreter handling this object */
2974
    ArchInfo *info;                /* info associated with mega-widget */
2975
    ArchOption *archOpt;           /* option that couldn't be accessed */
2976
{
2977
    Tcl_ResetResult(interp);
2978
 
2979
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2980
        "internal error: cannot access itk_option(", archOpt->switchName, ")",
2981
        (char*)NULL);
2982
 
2983
    if (info->itclObj->accessCmd) {
2984
        Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
2985
        Tcl_AppendToObj(resultPtr, " in widget \"", -1);
2986
        Tcl_GetCommandFullName(interp, info->itclObj->accessCmd, resultPtr);
2987
        Tcl_AppendToObj(resultPtr, "\"", -1);
2988
    }
2989
}
2990
 
2991
 
2992
/*
2993
 * ------------------------------------------------------------------------
2994
 *  Itk_GetArchInfo()
2995
 *
2996
 *  Finds the extra Archetype info associated with the given object.
2997
 *  Returns TCL_OK and a pointer to the info if found.  Returns
2998
 *  TCL_ERROR along with an error message in interp->result if not.
2999
 * ------------------------------------------------------------------------
3000
 */
3001
static int
3002
Itk_GetArchInfo(interp, contextObj, infoPtr)
3003
    Tcl_Interp *interp;            /* interpreter handling this object */
3004
    ItclObject *contextObj;        /* object with desired data */
3005
    ArchInfo **infoPtr;            /* returns:  pointer to extra info */
3006
{
3007
    Tcl_HashTable *objsWithArchInfo;
3008
    Tcl_HashEntry *entry;
3009
 
3010
    /*
3011
     *  If there is any problem finding the info, return an error.
3012
     */
3013
    objsWithArchInfo = ItkGetObjsWithArchInfo(interp);
3014
    entry = Tcl_FindHashEntry(objsWithArchInfo, (char*)contextObj);
3015
 
3016
    if (!entry) {
3017
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3018
            "internal error: no Archetype information for widget",
3019
            (char*)NULL);
3020
 
3021
        if (contextObj->accessCmd) {
3022
            Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
3023
            Tcl_AppendToObj(resultPtr, " \"", -1);
3024
            Tcl_GetCommandFullName(interp, contextObj->accessCmd, resultPtr);
3025
            Tcl_AppendToObj(resultPtr, "\"", -1);
3026
        }
3027
        return TCL_ERROR;
3028
    }
3029
 
3030
    /*
3031
     *  Otherwise, return the requested info.
3032
     */
3033
    *infoPtr = (ArchInfo*)Tcl_GetHashValue(entry);
3034
    return TCL_OK;
3035
}
3036
 
3037
 
3038
/*
3039
 * ------------------------------------------------------------------------
3040
 *  Itk_CreateArchComponent()
3041
 *
3042
 *  Creates the data representing a component widget within an Archetype
3043
 *  mega-widget.  Each component has an access command that is used to
3044
 *  communicate with it.  Each component is registered by its symbolic
3045
 *  name in the "itk_component" array.
3046
 *
3047
 *  Returns a pointer to the new record.  If anything goes wrong,
3048
 *  this returns NULL, along with an error message in the interpreter.
3049
 * ------------------------------------------------------------------------
3050
 */
3051
static ArchComponent*
3052
Itk_CreateArchComponent(interp, info, name, cdefn, accessCmd)
3053
    Tcl_Interp *interp;            /* interpreter managing the object */
3054
    ArchInfo *info;                /* info associated with mega-widget */
3055
    char *name;                    /* symbolic name for this component */
3056
    ItclClass *cdefn;              /* component created in this class */
3057
    Tcl_Command accessCmd;         /* access command for component */
3058
{
3059
    char *wname, *init;
3060
    ArchComponent *archComp;
3061
    ArchOption *archOpt;
3062
    Tk_Window tkwin;
3063
    Tcl_HashEntry *entry;
3064
    Tcl_HashSearch place;
3065
    ItclMember *memPtr;
3066
 
3067
    /*
3068
     *  Save this component in the itk_component() array.
3069
     */
3070
    wname = Tcl_GetCommandName(interp, accessCmd);
3071
    Tcl_SetVar2(interp, "itk_component", name, wname, 0);
3072
 
3073
    /*
3074
     *  If the symbolic name for the component is "hull", then this
3075
     *  is the toplevel or frame that embodies a mega-widget.  Update
3076
     *  the Archtype info to include the window token.
3077
     */
3078
    tkwin = Tk_NameToWindow(interp, wname, Tk_MainWindow(interp));
3079
 
3080
    if (strcmp(name, "hull") == 0) {
3081
        if (tkwin == NULL) {
3082
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3083
                "cannot find hull window with access command \"", wname, "\"",
3084
                (char*)NULL);
3085
            return NULL;
3086
        }
3087
        info->tkwin = tkwin;
3088
 
3089
        /*
3090
         *  We are now in a position to query configuration options
3091
         *  relative to this window.  Scan through all existing options
3092
         *  and update the initial values according to the X11 resource
3093
         *  database.
3094
         */
3095
        entry = Tcl_FirstHashEntry(&info->options, &place);
3096
        while (entry) {
3097
            archOpt = (ArchOption*)Tcl_GetHashValue(entry);
3098
 
3099
            init = NULL;
3100
            if (archOpt->resName && archOpt->resClass) {
3101
                init = Tk_GetOption(tkwin, archOpt->resName, archOpt->resClass);
3102
            }
3103
 
3104
            if (init && (!archOpt->init || strcmp(init, archOpt->init) != 0)) {
3105
                if (!archOpt->init) {
3106
                    ckfree(archOpt->init);
3107
                }
3108
                archOpt->init = (char*)ckalloc((unsigned)(strlen(init)+1));
3109
                strcpy(archOpt->init, init);
3110
 
3111
                if (Itk_ArchSetOption(interp, info,
3112
                    archOpt->switchName, init) != TCL_OK) {
3113
                    return NULL;
3114
                }
3115
            }
3116
            entry = Tcl_NextHashEntry(&place);
3117
        }
3118
    }
3119
 
3120
    /*
3121
     *  Create the record to represent this component.
3122
     */
3123
    archComp = (ArchComponent*)ckalloc(sizeof(ArchComponent));
3124
 
3125
    memPtr = (ItclMember*)ckalloc(sizeof(ItclMember));
3126
    memPtr->interp      = interp;
3127
    memPtr->classDefn   = cdefn;
3128
    memPtr->name        = NULL;
3129
    memPtr->fullname    = NULL;
3130
    memPtr->flags       = 0;
3131
    memPtr->protection  = ITCL_PUBLIC;
3132
    memPtr->code        = NULL;
3133
 
3134
    archComp->member     = memPtr;
3135
    archComp->accessCmd  = accessCmd;
3136
    archComp->tkwin      = tkwin;
3137
 
3138
    return archComp;
3139
}
3140
 
3141
 
3142
/*
3143
 * ------------------------------------------------------------------------
3144
 *  Itk_DelArchComponent()
3145
 *
3146
 *  Destroys an Archetype component record previously created by
3147
 *  Itk_CreateArchComponent().
3148
 * ------------------------------------------------------------------------
3149
 */
3150
static void
3151
Itk_DelArchComponent(archComp)
3152
    ArchComponent *archComp;  /* pointer to component data */
3153
{
3154
    ckfree((char*)archComp->member);
3155
    ckfree((char*)archComp);
3156
}
3157
 
3158
 
3159
/*
3160
 * ------------------------------------------------------------------------
3161
 *  Itk_GetArchOption()
3162
 *
3163
 *  Finds or creates the data representing a composite configuration
3164
 *  option for an Archetype mega-widget.  Each option acts as a single
3165
 *  entity, but is composed of several parts which propagate changes
3166
 *  down to the component widgets.  If the option already exists, then
3167
 *  the specified resource name and resource class must match the
3168
 *  existing definition.
3169
 *
3170
 *  If the option is created, an initial value for is determined by
3171
 *  querying the X11 resource database, and if this fails, the
3172
 *  hard-wired default value is used.
3173
 *
3174
 *  If successful, returns TCL_OK along with a pointer to the option
3175
 *  record.  Returns TCL_ERROR (along with an error message in the
3176
 *  interpreter) if anything goes wrong.
3177
 * ------------------------------------------------------------------------
3178
 */
3179
static int
3180
Itk_GetArchOption(interp, info, switchName, resName, resClass,
3181
    defVal, currVal, aoPtr)
3182
 
3183
    Tcl_Interp *interp;            /* interpreter managing the object */
3184
    ArchInfo *info;                /* info for Archetype mega-widget */
3185
    char *switchName;              /* name of command-line switch */
3186
    char *resName;                 /* resource name in X11 database */
3187
    char *resClass;                /* resource class name in X11 database */
3188
    char *defVal;                  /* last-resort default value */
3189
    char *currVal;                 /* current option value */
3190
    ArchOption **aoPtr;            /* returns: option record */
3191
{
3192
    int result = TCL_OK;
3193
 
3194
    int newEntry;
3195
    char *name;
3196
    ArchOption *archOpt;
3197
    Tcl_HashEntry *entry;
3198
 
3199
    /*
3200
     *  If the switch does not have a leading "-", add it on.
3201
     */
3202
    if (*switchName != '-') {
3203
        name = ckalloc((unsigned)(strlen(switchName)+2));
3204
        *name = '-';
3205
        strcpy(name+1, switchName);
3206
    } else {
3207
        name = switchName;
3208
    }
3209
 
3210
    /*
3211
     *  See if an option already exists with the switch name.
3212
     *  If it does, then make sure that the given resource name
3213
     *  and resource class match the existing definition.
3214
     */
3215
    entry = Tcl_CreateHashEntry(&info->options, name, &newEntry);
3216
    if (!newEntry) {
3217
        archOpt = (ArchOption*)Tcl_GetHashValue(entry);
3218
 
3219
        if (resName && !archOpt->resName) {
3220
            archOpt->resName = (char*)ckalloc((unsigned)(strlen(resName)+1));
3221
            strcpy(archOpt->resName, resName);
3222
        }
3223
        else if (resName && strcmp(archOpt->resName, resName) != 0) {
3224
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3225
                "bad resource name \"", resName, "\" for option \"",
3226
                name, "\": should be \"", archOpt->resName, "\"",
3227
                (char*)NULL);
3228
            result = TCL_ERROR;
3229
            goto getArchOptionDone;
3230
        }
3231
 
3232
        if (resClass && !archOpt->resClass) {
3233
            archOpt->resClass = (char*)ckalloc((unsigned)(strlen(resClass)+1));
3234
            strcpy(archOpt->resClass, resClass);
3235
        }
3236
        else if (resClass && strcmp(archOpt->resClass, resClass) != 0) {
3237
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3238
                "bad resource class \"", resClass, "\" for option \"",
3239
                name, "\": should be \"", archOpt->resClass, "\"",
3240
                (char*)NULL);
3241
            result = TCL_ERROR;
3242
            goto getArchOptionDone;
3243
        }
3244
 
3245
        if (!archOpt->init) {
3246
            Itk_InitArchOption(interp, info, archOpt, defVal, currVal);
3247
        }
3248
        *aoPtr = archOpt;
3249
 
3250
        result = TCL_OK;
3251
        goto getArchOptionDone;
3252
    }
3253
 
3254
    /*
3255
     *  Create the record to represent this option, and save it
3256
     *  in the option table.
3257
     */
3258
    archOpt = (ArchOption*)ckalloc(sizeof(ArchOption));
3259
 
3260
    archOpt->switchName = (char*)ckalloc((unsigned)(strlen(name)+1));
3261
    strcpy(archOpt->switchName, name);
3262
 
3263
    if (resName) {
3264
        archOpt->resName = (char*)ckalloc((unsigned)(strlen(resName)+1));
3265
        strcpy(archOpt->resName, resName);
3266
    }
3267
    else {
3268
        archOpt->resName = NULL;
3269
    }
3270
 
3271
    if (resClass) {
3272
        archOpt->resClass = (char*)ckalloc((unsigned)(strlen(resClass)+1));
3273
        strcpy(archOpt->resClass, resClass);
3274
    }
3275
    else {
3276
        archOpt->resClass = NULL;
3277
    }
3278
 
3279
    archOpt->flags = 0;
3280
    Itcl_InitList(&archOpt->parts);
3281
 
3282
    archOpt->init = NULL;
3283
    Itk_InitArchOption(interp,info,archOpt,defVal,currVal);
3284
 
3285
    Tcl_SetHashValue(entry, (ClientData)archOpt);
3286
    Itk_OptListAdd(&info->order, entry);
3287
 
3288
    *aoPtr = archOpt;
3289
 
3290
getArchOptionDone:
3291
    if (name != switchName) {
3292
        ckfree(name);
3293
    }
3294
    return result;
3295
}
3296
 
3297
/*
3298
 * ------------------------------------------------------------------------
3299
 *  Itk_InitArchOption()
3300
 *
3301
 *  Sets the initial value for a composite configuration option for
3302
 *  an Archetype mega-widget.  This is usually invoked when an option
3303
 *  is first created by Itk_GetArchOption().  It queries the X11
3304
 *  resource database for an initial value, and if nothing is found,
3305
 *  falls back on a last-resort value.  It stores the initial value
3306
 *  in the "itk_option" array, adds a copy to the option info, and
3307
 *  returns.
3308
 *
3309
 *  If successful, returns TCL_OK along with a pointer to the option
3310
 *  record.  Returns TCL_ERROR (along with an error message in the
3311
 *  interpreter) if anything goes wrong.
3312
 * ------------------------------------------------------------------------
3313
 */
3314
static void
3315
Itk_InitArchOption(interp, info, archOpt, defVal, currVal)
3316
    Tcl_Interp *interp;            /* interpreter managing the object */
3317
    ArchInfo *info;                /* info for Archetype mega-widget */
3318
    ArchOption *archOpt;           /* option to initialize */
3319
    char *defVal;                  /* last-resort default value */
3320
    char *currVal;                 /* current option value */
3321
{
3322
    char *init = NULL;
3323
 
3324
    int result;
3325
    char c, *ival;
3326
    ItclContext context;
3327
 
3328
    /*
3329
     *  If the option is already initialized, then abort.
3330
     */
3331
    if (archOpt->init) {
3332
        return;
3333
    }
3334
 
3335
    /*
3336
     *  If this widget has a Tk window, query the X11 resource
3337
     *  database for an initial option value.  If all else fails,
3338
     *  use the hard-wired default value.
3339
     */
3340
    if (archOpt->resName && archOpt->resClass && info->tkwin != NULL) {
3341
        init = Tk_GetOption(info->tkwin, archOpt->resName, archOpt->resClass);
3342
    }
3343
    if (init == NULL) {
3344
        init = defVal;
3345
    }
3346
 
3347
    /*
3348
     *  Normally, the initial value for the itk_option array is
3349
     *  the same as the initial value for the option.  Watch
3350
     *  out for the fixed Tk options (-class, -colormap, -screen
3351
     *  and -visual).  Since these cannot be modified later,
3352
     *  they must be set to their current value.
3353
     */
3354
    c = *(archOpt->switchName+1);
3355
 
3356
    if ((c == 'c' && strcmp(archOpt->switchName,"-class") == 0) ||
3357
        (c == 'c' && strcmp(archOpt->switchName,"-colormap") == 0) ||
3358
        (c == 's' && strcmp(archOpt->switchName,"-screen") == 0) ||
3359
        (c == 'v' && strcmp(archOpt->switchName,"-visual") == 0)) {
3360
        ival = currVal;
3361
    }
3362
    else {
3363
        ival = init;
3364
    }
3365
 
3366
    /*
3367
     *  Set the initial value in the itk_option array.
3368
     *  Since this might be called from the itk::option-parser
3369
     *  namespace, reinstall the object context.
3370
     */
3371
    result = Itcl_PushContext(interp, (ItclMember*)NULL,
3372
        info->itclObj->classDefn, info->itclObj, &context);
3373
 
3374
    if (result == TCL_OK) {
3375
        Tcl_SetVar2(interp, "itk_option", archOpt->switchName,
3376
            (ival) ? ival : "", 0);
3377
        Itcl_PopContext(interp, &context);
3378
    }
3379
 
3380
    if (ival) {
3381
        archOpt->init = (char*)ckalloc((unsigned)(strlen(ival)+1));
3382
        strcpy(archOpt->init, ival);
3383
    }
3384
}
3385
 
3386
/*
3387
 * ------------------------------------------------------------------------
3388
 *  Itk_DelArchOption()
3389
 *
3390
 *  Destroys an Archetype configuration option previously created by
3391
 *  Itk_CreateArchOption().
3392
 * ------------------------------------------------------------------------
3393
 */
3394
static void
3395
Itk_DelArchOption(archOpt)
3396
    ArchOption *archOpt;  /* pointer to option data */
3397
{
3398
    Itcl_ListElem *elem;
3399
    ArchOptionPart *optPart;
3400
 
3401
    /*
3402
     *  Delete all "parts" relating to component widgets.
3403
     */
3404
    elem = Itcl_FirstListElem(&archOpt->parts);
3405
    while (elem) {
3406
        optPart = (ArchOptionPart*)Itcl_GetListValue(elem);
3407
        Itk_DelOptionPart(optPart);
3408
        elem = Itcl_DeleteListElem(elem);
3409
    }
3410
 
3411
    /*
3412
     *  Free any remaining data.
3413
     */
3414
    ckfree(archOpt->switchName);
3415
    if (archOpt->resName) {
3416
        ckfree(archOpt->resName);
3417
    }
3418
    if (archOpt->resClass) {
3419
        ckfree(archOpt->resClass);
3420
    }
3421
    if (archOpt->init) {
3422
        ckfree(archOpt->init);
3423
    }
3424
    ckfree((char*)archOpt);
3425
}
3426
 
3427
 
3428
/*
3429
 * ------------------------------------------------------------------------
3430
 *  Itk_CreateOptionPart()
3431
 *
3432
 *  Creates the data representing a part within a configuration option
3433
 *  for an Archetype mega-widget.  Each part has a bit of code used to
3434
 *  apply configuration changes to some part of the mega-widget.
3435
 *  This is characterized by a bit of ClientData, and a "config"
3436
 *  procedure that knows how to execute it.  The ClientData is
3437
 *  automatically disposed of by the delete proc when this option
3438
 *  part is destroyed.
3439
 *
3440
 *  Option parts typically come from two sources:  Options defined
3441
 *  in the class definition, and options propagated upward from
3442
 *  component parts.
3443
 *
3444
 *  Returns a pointer to the new option part.
3445
 * ------------------------------------------------------------------------
3446
 */
3447
static ArchOptionPart*
3448
Itk_CreateOptionPart(interp, cdata, cproc, dproc, from)
3449
    Tcl_Interp *interp;              /* interpreter handling this request */
3450
    ClientData cdata;                /* data representing this part */
3451
    Itk_ConfigOptionPartProc *cproc; /* proc used to apply config changes */
3452
    Tcl_CmdDeleteProc *dproc;        /* proc used to clean up ClientData */
3453
    ClientData from;                 /* who contributed this option */
3454
{
3455
    ArchOptionPart *optPart;
3456
 
3457
    /*
3458
     *  Create the record to represent this part of the option.
3459
     */
3460
    optPart = (ArchOptionPart*)ckalloc(sizeof(ArchOptionPart));
3461
    optPart->clientData = cdata;
3462
    optPart->configProc = cproc;
3463
    optPart->deleteProc = dproc;
3464
    optPart->from       = from;
3465
 
3466
    return optPart;
3467
}
3468
 
3469
 
3470
/*
3471
 * ------------------------------------------------------------------------
3472
 *  Itk_AddOptionPart()
3473
 *
3474
 *  Integrates an option part into a composite configuration option
3475
 *  for an Archetype mega-widget.  If a composite option does not
3476
 *  yet exist with the specified switch name, it is created automatically.
3477
 *
3478
 *  Adds the option part onto the composite list, and reconfigures
3479
 *  the widget to update this option properly.
3480
 *
3481
 *  Returns TCL_OK on success, or TCL_ERROR (along with an error message
3482
 *  in the interpreter) if anything goes wrong.
3483
 * ------------------------------------------------------------------------
3484
 */
3485
static int
3486
Itk_AddOptionPart(interp, info, switchName, resName, resClass,
3487
    defVal, currVal, optPart, raOpt)
3488
 
3489
    Tcl_Interp *interp;              /* interpreter handling this request */
3490
    ArchInfo *info;                  /* info for Archetype mega-widget */
3491
    char *switchName;                /* name of command-line switch */
3492
    char *resName;                   /* resource name in X11 database */
3493
    char *resClass;                  /* resource class name in X11 database */
3494
    char *defVal;                    /* last-resort default value */
3495
    char *currVal;                   /* current value (or NULL) */
3496
    ArchOptionPart *optPart;         /* part to be added in */
3497
    ArchOption **raOpt;              /* returns: option containing new part */
3498
{
3499
    char *init = NULL;
3500
 
3501
    int result;
3502
    ArchOption *archOpt;
3503
    ItclContext context;
3504
 
3505
    *raOpt = NULL;
3506
 
3507
    /*
3508
     *  Find or create a composite option for the mega-widget.
3509
     */
3510
    result = Itk_GetArchOption(interp, info, switchName, resName, resClass,
3511
        defVal, currVal, &archOpt);
3512
 
3513
    if (result != TCL_OK) {
3514
        return TCL_ERROR;
3515
    }
3516
 
3517
    /*
3518
     *  Add the option part to the composite option.  If the
3519
     *  composite option has already been configured, then
3520
     *  simply update this part to the current value.  Otherwise,
3521
     *  leave the configuration to Itk_ArchInitCmd().
3522
     */
3523
    Itcl_AppendList(&archOpt->parts, (ClientData)optPart);
3524
 
3525
    if ((archOpt->flags & ITK_ARCHOPT_INIT) != 0) {
3526
 
3527
        result = Itcl_PushContext(interp, (ItclMember*)NULL,
3528
            info->itclObj->classDefn, info->itclObj, &context);
3529
 
3530
        if (result == TCL_OK) {
3531
            init = Tcl_GetVar2(interp, "itk_option", archOpt->switchName, 0);
3532
            Itcl_PopContext(interp, &context);
3533
        }
3534
 
3535
        if (!init) {
3536
            Itk_ArchOptAccessError(interp, info, archOpt);
3537
            return TCL_ERROR;
3538
        }
3539
 
3540
        if (!currVal || (strcmp(init,currVal) != 0)) {
3541
            result  = (*optPart->configProc)(interp, info->itclObj,
3542
                optPart->clientData, init);
3543
 
3544
            if (result != TCL_OK) {
3545
                Itk_ArchOptConfigError(interp, info, archOpt);
3546
                return TCL_ERROR;
3547
            }
3548
        }
3549
    }
3550
 
3551
    *raOpt = archOpt;
3552
    return TCL_OK;
3553
}
3554
 
3555
 
3556
/*
3557
 * ------------------------------------------------------------------------
3558
 *  Itk_FindArchOptionPart()
3559
 *
3560
 *  Searches for a specific piece of a composite configuration option
3561
 *  for an Archetype mega-widget.  The specified name is treated as the
3562
 *  "switch" name (e.g., "-option"), but this procedure will recognize
3563
 *  it even without the leading "-".
3564
 *
3565
 *  Returns a pointer to the option with the matching switch name and
3566
 *  source, or NULL if the option is not recognized.
3567
 * ------------------------------------------------------------------------
3568
 */
3569
static ArchOptionPart*
3570
Itk_FindArchOptionPart(info, switchName, from)
3571
    ArchInfo *info;                /* info for Archetype mega-widget */
3572
    char *switchName;              /* name of command-line switch */
3573
    ClientData from;               /* who contributed this option */
3574
{
3575
    ArchOptionPart *optPart = NULL;
3576
 
3577
    char *name;
3578
    Tcl_HashEntry *entry;
3579
    ArchOption *archOpt;
3580
    ArchOptionPart *op;
3581
    Itcl_ListElem *elem;
3582
 
3583
    /*
3584
     *  If the switch does not have a leading "-", add it on.
3585
     */
3586
    if (*switchName != '-') {
3587
        name = ckalloc((unsigned)(strlen(switchName)+2));
3588
        *name = '-';
3589
        strcpy(name+1, switchName);
3590
    } else {
3591
        name = switchName;
3592
    }
3593
 
3594
    /*
3595
     *  Look for a composite option, and then for a part with the
3596
     *  matching source.
3597
     */
3598
    entry = Tcl_FindHashEntry(&info->options, name);
3599
 
3600
    if (entry) {
3601
        archOpt = (ArchOption*)Tcl_GetHashValue(entry);
3602
        elem = Itcl_FirstListElem(&archOpt->parts);
3603
        while (elem) {
3604
            op = (ArchOptionPart*)Itcl_GetListValue(elem);
3605
            if (op->from == from) {
3606
                optPart = op;
3607
                break;
3608
            }
3609
            elem = Itcl_NextListElem(elem);
3610
        }
3611
    }
3612
 
3613
    if (name != switchName) {
3614
        ckfree(name);
3615
    }
3616
    return optPart;
3617
}
3618
 
3619
 
3620
/*
3621
 * ------------------------------------------------------------------------
3622
 *  Itk_RemoveArchOptionPart()
3623
 *
3624
 *  Searches for a specific piece of a composite configuration option
3625
 *  for an Archetype mega-widget.  The specified name is treated as the
3626
 *  "switch" name (e.g., "-option"), but this procedure will recognize
3627
 *  it even without the leading "-".  If an option part with the
3628
 *  specified name and source is found on the list, it is removed.
3629
 *
3630
 *  NOTE:  This procedure assumes that there is a valid object context
3631
 *    and a call frame supporting object data member access.  It is
3632
 *    usually called from within the methods of the Archetype base
3633
 *    class, so this is a good assumption.  If it is called anywhere
3634
 *    else, the caller is responsible for installing the object context
3635
 *    and setting up a call frame.
3636
 *
3637
 *  Returns non-zero if the part was found and removed, and 0 otherwise.
3638
 * ------------------------------------------------------------------------
3639
 */
3640
static int
3641
Itk_RemoveArchOptionPart(info, switchName, from)
3642
    ArchInfo *info;                /* info for Archetype mega-widget */
3643
    char *switchName;              /* name of command-line switch */
3644
    ClientData from;               /* who contributed this option */
3645
{
3646
    int result = 0;
3647
 
3648
    char *name;
3649
    Tcl_HashEntry *entry;
3650
    ArchOption *archOpt;
3651
    ArchOptionPart *op;
3652
    Itcl_ListElem *elem;
3653
 
3654
 
3655
    /*
3656
     *  If the switch does not have a leading "-", add it on.
3657
     */
3658
    if (*switchName != '-') {
3659
        name = ckalloc((unsigned)(strlen(switchName)+2));
3660
        *name = '-';
3661
        strcpy(name+1, switchName);
3662
    } else {
3663
        name = switchName;
3664
    }
3665
 
3666
    /*
3667
     *  Look for a composite option, and then for a part with the
3668
     *  matching source.  If found, remove it.
3669
     */
3670
    entry = Tcl_FindHashEntry(&info->options, name);
3671
 
3672
    if (entry) {
3673
        archOpt = (ArchOption*)Tcl_GetHashValue(entry);
3674
        elem = Itcl_FirstListElem(&archOpt->parts);
3675
        while (elem) {
3676
            op = (ArchOptionPart*)Itcl_GetListValue(elem);
3677
            if (op->from == from) {
3678
                Itk_DelOptionPart(op);
3679
                result = 1;
3680
                elem = Itcl_DeleteListElem(elem);
3681
            }
3682
            else {
3683
                elem = Itcl_NextListElem(elem);
3684
            }
3685
        }
3686
 
3687
        /*
3688
         *  If this option is now dead (no parts left), then
3689
         *  remove it from the widget.  Be careful to delete it
3690
         *  from the "itk_option" array as well.
3691
         */
3692
        if (Itcl_GetListLength(&archOpt->parts) == 0) {
3693
            Tcl_UnsetVar2(info->itclObj->classDefn->interp,
3694
                "itk_option", archOpt->switchName, 0);
3695
 
3696
            Itk_DelArchOption(archOpt);
3697
            Itk_OptListRemove(&info->order, entry);
3698
            Tcl_DeleteHashEntry(entry);
3699
        }
3700
    }
3701
 
3702
    if (name != switchName) {
3703
        ckfree(name);
3704
    }
3705
    return result;
3706
}
3707
 
3708
 
3709
/*
3710
 * ------------------------------------------------------------------------
3711
 *  Itk_IgnoreArchOptionPart()
3712
 *
3713
 *  Removes the specified part from a composite configuration option
3714
 *  for an Archetype mega-widget.  This is usually called before
3715
 *  keeping or renaming an option, to make sure that the option
3716
 *  is not already integrated elsewhere on the composite list.
3717
 *  This also handles the action of "ignoring" a configuration option.
3718
 *
3719
 *  NOTE:  This procedure assumes that there is a valid object context
3720
 *    and a call frame supporting object data member access.  It is
3721
 *    usually called from within the methods of the Archetype base
3722
 *    class, so this is a good assumption.  If it is called anywhere
3723
 *    else, the caller is responsible for installing the object context
3724
 *    and setting up a call frame.
3725
 *
3726
 *  Returns non-zero if the part was found and removed, and 0 otherwise.
3727
 * ------------------------------------------------------------------------
3728
 */
3729
static int
3730
Itk_IgnoreArchOptionPart(info, opt)
3731
    ArchInfo *info;                /* info for Archetype mega-widget */
3732
    GenericConfigOpt *opt;         /* part to be ignored */
3733
{
3734
    int result = 0;
3735
 
3736
    Tcl_HashEntry *entry;
3737
    ArchOptionPart *op;
3738
    Itcl_ListElem *elem;
3739
 
3740
    /*
3741
     *  If the part is not integrated, then do nothing.
3742
     *  Otherwise, find the missing part and remove it.
3743
     */
3744
    if (opt->integrated) {
3745
        elem = Itcl_FirstListElem(&opt->integrated->parts);
3746
        while (elem) {
3747
            op = (ArchOptionPart*)Itcl_GetListValue(elem);
3748
            if (op == opt->optPart) {
3749
                Itk_DelOptionPart(op);
3750
                result = 1;
3751
                elem = Itcl_DeleteListElem(elem);
3752
            }
3753
            else {
3754
                elem = Itcl_NextListElem(elem);
3755
            }
3756
        }
3757
 
3758
        /*
3759
         *  If this option is now dead (no parts left), then
3760
         *  remove it from the widget.  Be careful to delete it
3761
         *  from the "itk_option" array as well.
3762
         */
3763
        if (Itcl_GetListLength(&opt->integrated->parts) == 0) {
3764
            Tcl_UnsetVar2(info->itclObj->classDefn->interp,
3765
                "itk_option", opt->integrated->switchName, 0);
3766
 
3767
            entry = Tcl_FindHashEntry(&info->options,
3768
                opt->integrated->switchName);
3769
 
3770
            if (entry) {
3771
                Itk_OptListRemove(&info->order, entry);
3772
                Tcl_DeleteHashEntry(entry);
3773
            }
3774
            Itk_DelArchOption(opt->integrated);
3775
        }
3776
 
3777
        /*
3778
         *  Forget that this part was ever integrated.
3779
         */
3780
        opt->integrated = NULL;
3781
        opt->optPart = NULL;
3782
    }
3783
    return result;
3784
}
3785
 
3786
 
3787
/*
3788
 * ------------------------------------------------------------------------
3789
 *  Itk_DelOptionPart()
3790
 *
3791
 *  Destroys part of an Archetype configuration option created by
3792
 *  Itk_CreateOptionPart().
3793
 * ------------------------------------------------------------------------
3794
 */
3795
static void
3796
Itk_DelOptionPart(optPart)
3797
    ArchOptionPart *optPart;  /* option part data to be destroyed */
3798
{
3799
    if (optPart->clientData && optPart->deleteProc) {
3800
        (*optPart->deleteProc)(optPart->clientData);
3801
    }
3802
    ckfree((char*)optPart);
3803
}
3804
 
3805
 
3806
/*
3807
 * ------------------------------------------------------------------------
3808
 *  Itk_CreateConfigCmdline()
3809
 *
3810
 *  Creates the data representing a command line for a "configure"
3811
 *  operation.  Each "configure" command has the following form:
3812
 *
3813
 *      <object> configure -<option> <value>
3814
 *
3815
 *  The first three arguments are created in this procedure.  The
3816
 *  <value> argument is reinitialized each time the command is
3817
 *  executed.
3818
 *
3819
 *  Returns a pointer to the new command record.
3820
 * ------------------------------------------------------------------------
3821
 */
3822
static ConfigCmdline*
3823
Itk_CreateConfigCmdline(interp, accessCmd, switchName)
3824
    Tcl_Interp *interp;              /* interpreter handling this request */
3825
    Tcl_Command accessCmd;           /* command for <object> being config'd */
3826
    char *switchName;                /* switch name of option being config'd */
3827
{
3828
    int i;
3829
    ConfigCmdline *cmdlinePtr;
3830
    Tcl_Obj *objPtr;
3831
 
3832
    /*
3833
     *  Create the record to represent this part of the option.
3834
     */
3835
    cmdlinePtr = (ConfigCmdline*)ckalloc(sizeof(ConfigCmdline));
3836
 
3837
    objPtr = Tcl_NewStringObj((char*)NULL, 0);
3838
    Tcl_GetCommandFullName(interp, accessCmd, objPtr);
3839
    cmdlinePtr->objv[0] = objPtr;
3840
    cmdlinePtr->objv[1] = Tcl_NewStringObj("configure", -1);
3841
    cmdlinePtr->objv[2] = Tcl_NewStringObj(switchName, -1);
3842
 
3843
    for (i=0; i < 3; i++) {
3844
        Tcl_IncrRefCount(cmdlinePtr->objv[i]);
3845
    }
3846
    return cmdlinePtr;
3847
}
3848
 
3849
/*
3850
 * ------------------------------------------------------------------------
3851
 *  Itk_DeleteConfigCmdline()
3852
 *
3853
 *  Deletes the data created by Itk_CreateConfigCmdline.  Called
3854
 *  when an option part is deleted to free up the memory associated
3855
 *  with the configure command.
3856
 * ------------------------------------------------------------------------
3857
 */
3858
static void
3859
Itk_DeleteConfigCmdline(cdata)
3860
    ClientData cdata;                /* command to be freed */
3861
{
3862
    ConfigCmdline *cmdlinePtr = (ConfigCmdline*)cdata;
3863
    int i;
3864
 
3865
    /*
3866
     *  TRICKY NOTE:  Decrement the reference counts for only the
3867
     *    first three arguments on the command line.  The fourth
3868
     *    argument is released after each configure operation.
3869
     */
3870
    for (i=0; i < 3; i++) {
3871
        Tcl_DecrRefCount(cmdlinePtr->objv[i]);
3872
    }
3873
    ckfree((char*)cmdlinePtr);
3874
}
3875
 
3876
 
3877
/*
3878
 * ------------------------------------------------------------------------
3879
 *  Itk_CreateGenericOptTable()
3880
 *
3881
 *  Parses a string describing a widget's configuration options (of the
3882
 *  form returned by the usual widget "configure" method) and creates
3883
 *  a hash table for easy lookup of option information.  Entries in
3884
 *  the hash table are indexed by switch names like "-background".
3885
 *  Values are GenericConfigOpt records.  Alias options like "-bg" are
3886
 *  ignored.
3887
 *
3888
 *  This table is used by option parsing commands in "itk::option-parser"
3889
 *  to validate widget options.
3890
 *
3891
 *  Returns a pointer to a new hash table, which should later be freed
3892
 *  via Itk_DelGenericOptTable().  Returns NULL if an error is found in
3893
 *  the configuration list.
3894
 * ------------------------------------------------------------------------
3895
 */
3896
static Tcl_HashTable*
3897
Itk_CreateGenericOptTable(interp, options)
3898
    Tcl_Interp *interp;          /* interpreter handling this request */
3899
    char *options;               /* string description of config options */
3900
{
3901
    int confc;
3902
    char **confv = NULL;
3903
    int optc;
3904
    char **optv = NULL;
3905
 
3906
    int i, newEntry;
3907
    Tcl_HashTable *tPtr;
3908
    Tcl_HashEntry *entry;
3909
    GenericConfigOpt *info;
3910
 
3911
    tPtr = (Tcl_HashTable*)ckalloc(sizeof(Tcl_HashTable));
3912
    Tcl_InitHashTable(tPtr, TCL_STRING_KEYS);
3913
 
3914
    /*
3915
     *  Split the list of options and store each one in the table.
3916
     *  Only consider options with all 5 required components.  Avoid
3917
     *  aliases like "-bg".
3918
     */
3919
    if (Tcl_SplitList(interp, options, &confc, &confv) != TCL_OK) {
3920
        goto tableFail;
3921
    }
3922
    for (i=0; i < confc; i++) {
3923
        if (Tcl_SplitList(interp, confv[i], &optc, &optv) != TCL_OK) {
3924
            goto tableFail;
3925
        }
3926
        if (optc == 5) {    /* avoid aliased options */
3927
            entry = Tcl_CreateHashEntry(tPtr, optv[0], &newEntry);
3928
            if (newEntry) {
3929
                info = (GenericConfigOpt*)ckalloc(sizeof(GenericConfigOpt));
3930
                info->switchName = optv[0];
3931
                info->resName    = optv[1];
3932
                info->resClass   = optv[2];
3933
                info->init       = optv[3];
3934
                info->value      = optv[4];
3935
                info->storage    = optv;
3936
                info->integrated = NULL;
3937
                info->optPart    = NULL;
3938
                Tcl_SetHashValue(entry, (ClientData)info);
3939
            }
3940
        }
3941
        else {
3942
            ckfree((char*)optv);
3943
        }
3944
    }
3945
 
3946
    ckfree((char*)confv);
3947
    return tPtr;
3948
 
3949
tableFail:
3950
    if (confv) {
3951
        ckfree((char*)confv);
3952
    }
3953
    Itk_DelGenericOptTable(tPtr);
3954
    return NULL;
3955
}
3956
 
3957
 
3958
/*
3959
 * ------------------------------------------------------------------------
3960
 *  Itk_DelGenericOptTable()
3961
 *
3962
 *  Destroys an option table previously created by
3963
 *  Itk_CreateGenericOptTable() and frees all memory associated with it.
3964
 *  Should be called whenever a table is no longer needed, to free up
3965
 *  resources.
3966
 * ------------------------------------------------------------------------
3967
 */
3968
static void
3969
Itk_DelGenericOptTable(tPtr)
3970
    Tcl_HashTable *tPtr;  /* option table to be destroyed */
3971
{
3972
    Tcl_HashEntry *entry;
3973
    Tcl_HashSearch place;
3974
    GenericConfigOpt *info;
3975
 
3976
    /*
3977
     *  Scan through all options in the table and free entries.
3978
     */
3979
    entry = Tcl_FirstHashEntry(tPtr, &place);
3980
    while (entry) {
3981
        info = (GenericConfigOpt*)Tcl_GetHashValue(entry);
3982
        ckfree((char*)info->storage);
3983
        ckfree((char*)info);
3984
        entry = Tcl_NextHashEntry(&place);
3985
    }
3986
 
3987
    Tcl_DeleteHashTable(tPtr);
3988
    ckfree((char*)tPtr);
3989
}
3990
 
3991
 
3992
/*
3993
 * ------------------------------------------------------------------------
3994
 *  Itk_CreateGenericOpt()
3995
 *
3996
 *  Parses a string describing a widget's configuration option (of the
3997
 *  form returned by the usual widget "configure" method) and creates
3998
 *  a representation for one option.  Similar to
3999
 *  Itk_CreateGenericOptTable(), but only handles one option at a
4000
 *  time.
4001
 *
4002
 *  Returns a pointer to the option info, which should later be freed
4003
 *  via Itk_DelGenericOpt().  Returns NULL (along with an error
4004
 *  message in the interpreter) if an error is found.
4005
 *
4006
 *  SIDE EFFECT:  Resets the interpreter result.
4007
 * ------------------------------------------------------------------------
4008
 */
4009
static GenericConfigOpt*
4010
Itk_CreateGenericOpt(interp, switchName, accessCmd)
4011
    Tcl_Interp *interp;          /* interpreter handling this request */
4012
    char *switchName;            /* command-line switch for option */
4013
    Tcl_Command accessCmd;       /* access command for component */
4014
{
4015
    GenericConfigOpt *genericOpt = NULL;
4016
    Tcl_Obj *codePtr = NULL;
4017
 
4018
    int optc, result;
4019
    char **optv;
4020
    char *name, *info;
4021
    Tcl_Obj *resultPtr;
4022
 
4023
    /*
4024
     *  If the switch does not have a leading "-", add it on.
4025
     */
4026
    if (*switchName != '-') {
4027
        name = ckalloc((unsigned)(strlen(switchName)+2));
4028
        *name = '-';
4029
        strcpy(name+1, switchName);
4030
    } else {
4031
        name = switchName;
4032
    }
4033
 
4034
    /*
4035
     *  Build a "configure" command to query info for the requested
4036
     *  option.  Evaluate the command and get option info.
4037
     */
4038
    codePtr = Tcl_NewStringObj((char*)NULL, 0);
4039
    Tcl_IncrRefCount(codePtr);
4040
 
4041
    Tcl_GetCommandFullName(interp, accessCmd, codePtr);
4042
    Tcl_AppendToObj(codePtr, " configure ", -1);
4043
    Tcl_AppendToObj(codePtr, name, -1);
4044
 
4045
      /* CYGNUS LOCAL - Fix for Tcl8.1 */
4046
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
4047
    if (Tcl_EvalObj(interp, codePtr) != TCL_OK) {
4048
#else
4049
      if (Tcl_EvalObj(interp, codePtr, 0) != TCL_OK) {
4050
#endif
4051
      /* END CYGNUS LOCAL */
4052
        goto optionDone;
4053
    }
4054
 
4055
    /*
4056
     *  Only consider options with all 5 required components.  Avoid
4057
     *  aliases like "-bg".
4058
     */
4059
    resultPtr = Tcl_GetObjResult(interp);
4060
    Tcl_IncrRefCount(resultPtr);
4061
    info = Tcl_GetStringFromObj(resultPtr, (int*)NULL);
4062
 
4063
    result = Tcl_SplitList(interp, info, &optc, &optv);
4064
 
4065
    Tcl_DecrRefCount(resultPtr);
4066
 
4067
    if (result != TCL_OK) {
4068
        goto optionDone;
4069
    }
4070
    if (optc == 5) {    /* avoid aliased options */
4071
        genericOpt = (GenericConfigOpt*)ckalloc(sizeof(GenericConfigOpt));
4072
        genericOpt->switchName = optv[0];
4073
        genericOpt->resName    = optv[1];
4074
        genericOpt->resClass   = optv[2];
4075
        genericOpt->init       = optv[3];
4076
        genericOpt->value      = optv[4];
4077
        genericOpt->storage    = optv;
4078
        genericOpt->integrated = NULL;
4079
        genericOpt->optPart    = NULL;
4080
    }
4081
    else {
4082
        ckfree((char*)optv);
4083
    }
4084
 
4085
optionDone:
4086
    if (name != switchName) {
4087
        ckfree(name);
4088
    }
4089
    if (codePtr) {
4090
        Tcl_DecrRefCount(codePtr);
4091
    }
4092
    if (genericOpt) {
4093
        Tcl_ResetResult(interp);
4094
    }
4095
    return genericOpt;
4096
}
4097
 
4098
 
4099
/*
4100
 * ------------------------------------------------------------------------
4101
 *  Itk_DelGenericOpt()
4102
 *
4103
 *  Destroys a generic option previously created by Itk_CreateGenericOpt()
4104
 *  and frees all memory associated with it.  Should be called whenever
4105
 *  an option representation is no longer needed, to free up resources.
4106
 * ------------------------------------------------------------------------
4107
 */
4108
static void
4109
Itk_DelGenericOpt(opt)
4110
    GenericConfigOpt *opt;  /* option info to be destroyed */
4111
{
4112
    ckfree((char*)opt->storage);
4113
    ckfree((char*)opt);
4114
}
4115
 
4116
 
4117
/*
4118
 * ------------------------------------------------------------------------
4119
 *  ItkGetObjsWithArchInfo()
4120
 *
4121
 *  Returns a pointer to a hash table containing the list of registered
4122
 *  objects in the specified interpreter.  If the hash table does not
4123
 *  already exist, it is created.
4124
 * ------------------------------------------------------------------------
4125
 */
4126
static Tcl_HashTable*
4127
ItkGetObjsWithArchInfo(interp)
4128
    Tcl_Interp *interp;  /* interpreter handling this registration */
4129
{
4130
    Tcl_HashTable* objTable;
4131
 
4132
    /*
4133
     *  If the registration table does not yet exist, then create it.
4134
     */
4135
    objTable = (Tcl_HashTable*)Tcl_GetAssocData(interp,
4136
        "itk_objsWithArchInfo", (Tcl_InterpDeleteProc**)NULL);
4137
 
4138
    if (!objTable) {
4139
        objTable = (Tcl_HashTable*)ckalloc(sizeof(Tcl_HashTable));
4140
        Tcl_InitHashTable(objTable, TCL_ONE_WORD_KEYS);
4141
        Tcl_SetAssocData(interp, "itk_objsWithArchInfo",
4142
            ItkFreeObjsWithArchInfo, (ClientData)objTable);
4143
    }
4144
    return objTable;
4145
}
4146
 
4147
/*
4148
 * ------------------------------------------------------------------------
4149
 *  ItkFreeObjsWithArchInfo()
4150
 *
4151
 *  When an interpreter is deleted, this procedure is called to
4152
 *  free up the associated data created by ItkGetObjsWithArchInfo.
4153
 * ------------------------------------------------------------------------
4154
 */
4155
static void
4156
ItkFreeObjsWithArchInfo(clientData, interp)
4157
    ClientData clientData;       /* associated data */
4158
    Tcl_Interp *interp;          /* interpreter being freed */
4159
{
4160
    Tcl_HashTable *tablePtr = (Tcl_HashTable*)clientData;
4161
    Tcl_HashSearch place;
4162
    Tcl_HashEntry *entry;
4163
 
4164
    entry = Tcl_FirstHashEntry(tablePtr, &place);
4165
    while (entry) {
4166
        Itk_DelArchInfo( Tcl_GetHashValue(entry) );
4167
        entry = Tcl_NextHashEntry(&place);
4168
    }
4169
 
4170
    Tcl_DeleteHashTable(tablePtr);
4171
    ckfree((char*)tablePtr);
4172
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.