1 /* -*-mode: C; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*- */
2
3 /* $Id: tixDiStyle.c,v 1.2.2.1 2002/01/24 08:59:32 idiscovery Exp $ */
4
5 /*
6 * tixDiStyle.c --
7 *
8 * This file implements the "Display Item Styles" in the Tix library.
9 *
10 * Copyright (c) 1996, Expert Interface Technologies
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 *
16 */
17
18 #include "tixPort.h"
19 #include "tix.h"
20 #include "tixInt.h"
21 #include "tkInt.h"
22
23 #ifdef _LANG
24 #define FORWARD extern
25 #define LINKAGE
26 #define DItemStyleParseProc TixDItemStyleParseProc
27 #define DItemStylePrintProc TixDItemStylePrintProc
28 #else
29 #define FORWARD static
30 #define LINKAGE static
31 #endif
32
33
34
35 typedef struct StyleLink {
36 Tix_DItemInfo * diTypePtr;
37 Tix_DItemStyle* stylePtr;
38 struct StyleLink * next;
39 } StyleLink;
40
41 typedef struct StyleInfo {
42 Tix_StyleTemplate * tmplPtr;
43 Tix_StyleTemplate tmpl;
44 StyleLink * linkHead;
45 } StyleInfo;
46
47
48 FORWARD int DItemStyleParseProc _ANSI_ARGS_((ClientData clientData,
49 Tcl_Interp *interp, Tk_Window tkwin,
50 Tcl_Obj * value,char *widRec, int offset));
51 FORWARD Tcl_Obj * DItemStylePrintProc _ANSI_ARGS_((
52 ClientData clientData, Tk_Window tkwin,
53 char *widRec, int offset,
54 Tcl_FreeProc **freeProcPtr));
55 static Tix_DItemStyle* FindDefaultStyle _ANSI_ARGS_((Tcl_Interp *interp,
56 Tix_DItemInfo * diTypePtr, Tk_Window tkwin));
57 static Tix_DItemStyle* FindStyle _ANSI_ARGS_((
58 char *styleName, Tcl_Interp *interp));
59 static Tix_DItemStyle* GetDItemStyle _ANSI_ARGS_((
60 Tix_DispData * ddPtr, Tix_DItemInfo * diTypePtr,
61 char * styleName, int *isNew_ret));
62 static void InitHashTables _ANSI_ARGS_((void));
63 static void ListAdd _ANSI_ARGS_((Tix_DItemStyle * stylePtr,
64 Tix_DItem *iPtr));
65 static void ListDelete _ANSI_ARGS_((Tix_DItemStyle * stylePtr,
66 Tix_DItem *iPtr));
67 static void ListDeleteAll _ANSI_ARGS_((Tix_DItemStyle * stylePtr));
68 static void StyleCmdDeletedProc _ANSI_ARGS_((
69 ClientData clientData));
70 static int StyleCmd _ANSI_ARGS_((ClientData clientData,
71 Tcl_Interp *interp, int argc, char **argv));
72 static int StyleConfigure _ANSI_ARGS_((Tcl_Interp *interp,
73 Tix_DItemStyle* stylePtr, int argc,
74 char **argv, int flags));
75 static void StyleDestroy _ANSI_ARGS_((char *clientData));
76 static void DeleteStyle _ANSI_ARGS_((Tix_DItemStyle * stylePtr));
77 static void DefWindowStructureProc _ANSI_ARGS_((
78 ClientData clientData, XEvent *eventPtr));
79 static void RefWindowStructureProc _ANSI_ARGS_((
80 ClientData clientData, XEvent *eventPtr));
81 static void SetDefaultStyle _ANSI_ARGS_((Tix_DItemInfo *diTypePtr,
82 Tk_Window tkwin, Tix_DItemStyle * stylePtr));
83 static Tcl_HashTable * GetDefaultTable _ANSI_ARGS_((Tcl_Interp *interp));
84 static Tcl_HashTable * GetStyleTable _ANSI_ARGS_((Tcl_Interp *interp));
85 void DestroyDefaultTable _ANSI_ARGS_((ClientData clientData,
86 Tcl_Interp *interp));
87 void DestroyStyleTable _ANSI_ARGS_((ClientData clientData,
88 Tcl_Interp *interp));
89
90 static TIX_DECLARE_SUBCMD(StyleConfigCmd);
91 static TIX_DECLARE_SUBCMD(StyleCGetCmd);
92 static TIX_DECLARE_SUBCMD(StyleDeleteCmd);
93 extern TIX_DECLARE_SUBCMD(Tix_ItemStyleCmd);
94
95 static int tableInited = 0;
96
97 void
DestroyDefaultTable(clientData,interp)98 DestroyDefaultTable(clientData,interp)
99 ClientData clientData;
100 Tcl_Interp *interp;
101 {
102 Tcl_DeleteHashTable((Tcl_HashTable *) clientData);
103 ckfree((char *) clientData);
104 }
105
106 void
DestroyStyleTable(clientData,interp)107 DestroyStyleTable(clientData,interp)
108 ClientData clientData;
109 Tcl_Interp *interp;
110 {
111 Tcl_DeleteHashTable((Tcl_HashTable *) clientData);
112 ckfree((char *) clientData);
113 }
114
115 Tcl_HashTable *
GetDefaultTable(interp)116 GetDefaultTable(interp)
117 Tcl_Interp *interp;
118 {
119 Tcl_HashTable *table = (Tcl_HashTable *) Tcl_GetAssocData(interp, "TixDefaultStyle", NULL);
120 if (table == NULL) {
121 table = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
122 Tcl_InitHashTable(table, TCL_ONE_WORD_KEYS);
123 Tcl_SetAssocData(interp, "TixDefaultStyle", DestroyDefaultTable,
124 (ClientData) table);
125 }
126 return table;
127 }
128
129 void
InitHashTables(void)130 InitHashTables _ANSI_ARGS_((void))
131 {
132 }
133
134 Tcl_HashTable *
GetStyleTable(interp)135 GetStyleTable(interp)
136 Tcl_Interp *interp;
137 {
138 Tcl_HashTable *table = (Tcl_HashTable *) Tcl_GetAssocData(interp, "TixStyles", NULL);
139 if (table == NULL) {
140 table = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
141 Tcl_InitHashTable(table, TCL_STRING_KEYS);
142 Tcl_SetAssocData(interp, "TixStyles", DestroyStyleTable,
143 (ClientData) table);
144 }
145 return table;
146 }
147
148
149 /*
150 *--------------------------------------------------------------
151 *
152 * TixDItemStyleFree --
153 *
154 * When an item does not need a style anymore (when the item
155 * is destroyed, e.g.), it must call this procedute to free the
156 * style).
157 *
158 * Results:
159 * Nothing
160 *
161 * Side effects:
162 * The item is freed from the list of attached items in the style.
163 * Also, the style will be freed if it was already destroyed and
164 * it has no more items attached to it.
165 *
166 *--------------------------------------------------------------
167 */
TixDItemStyleFree(iPtr,stylePtr)168 void TixDItemStyleFree(iPtr, stylePtr)
169 Tix_DItem *iPtr;
170 Tix_DItemStyle * stylePtr;
171 {
172 ListDelete(stylePtr, iPtr);
173 }
174
175 /*
176 *--------------------------------------------------------------
177 *
178 * Tix_ItemStyleCmd --
179 *
180 * This procedure is invoked to process the "tixItemStyle" Tcl
181 * command.
182 *
183 * Results:
184 * A standard Tcl result.
185 *
186 * Side effects:
187 * A new widget is created and configured.
188 *
189 *--------------------------------------------------------------
190 */
191 int
Tix_ItemStyleCmd(clientData,interp,argc,argv)192 Tix_ItemStyleCmd(clientData, interp, argc, argv)
193 ClientData clientData;
194 Tcl_Interp *interp; /* Current interpreter. */
195 int argc; /* Number of arguments. */
196 char **argv; /* Argument strings. */
197 {
198 Tix_DItemInfo * diTypePtr;
199 Tk_Window tkwin = (Tk_Window)clientData;
200 char * styleName = NULL;
201 Tix_DispData dispData;
202 char buff[100];
203 int i, n;
204 static int counter = 0;
205 Tix_DItemStyle * stylePtr;
206
207 if (argc < 2) {
208 return Tix_ArgcError(interp, argc, argv, 1,
209 "itemtype ?option value ...");
210 }
211
212 if ((diTypePtr=Tix_GetDItemType(interp, argv[1])) == NULL) {
213 return TCL_ERROR;
214 }
215
216 /*
217 * Parse the -refwindow option: this tells the style to use this
218 * window to query the default values for background, foreground
219 * etc. Usually, you should set the -refwindow to the window that
220 * holds the display items which are controlled by this style.
221 */
222 if (argc > 2) {
223 size_t len;
224 if (argc %2 != 0) {
225 Tcl_AppendResult(interp, "value for \"", argv[argc-1],
226 "\" missing", NULL);
227 return TCL_ERROR;
228 }
229 for (n=i=2; i<argc; i+=2) {
230 len = strlen(argv[i]);
231 if (strncmp(argv[i], "-refwindow", len) == 0) {
232 if ((tkwin=Tk_NameToWindow(interp,argv[i+1],tkwin)) == NULL) {
233 return TCL_ERROR;
234 }
235 continue;
236 }
237 if (strncmp(argv[i], "-stylename", len) == 0) {
238 styleName = argv[i+1];
239 if (FindStyle(styleName, interp) != NULL) {
240 Tcl_AppendResult(interp, "style \"", argv[i+1],
241 "\" already exist", NULL);
242 return TCL_ERROR;
243 }
244 continue;
245 }
246
247 if (n!=i) {
248 #if 0
249 objv[n] = objv[i];
250 objv[n+1] = objv[i+1];
251 #else
252 Tcl_SetStringObj(objv[n],Tcl_GetString(objv[i]),-1);
253 Tcl_SetStringObj(objv[n+1],Tcl_GetString(objv[i+1]),-1);
254 /* XXX ??? return TCL_ERROR; */
255 #endif
256 }
257 n+=2;
258 }
259 argc = n;
260 }
261
262 if (styleName == NULL) {
263 /*
264 * No name is given, we'll make a unique name by default
265 * (ToDo: check if the name has already been used)
266 */
267 sprintf(buff, "tixStyle%d", counter++);
268 styleName = buff;
269 }
270
271 dispData.interp = interp;
272 dispData.display = Tk_Display(tkwin);
273 dispData.tkwin = tkwin;
274
275 if ((stylePtr = GetDItemStyle(&dispData, diTypePtr,
276 styleName, NULL)) == NULL) {
277 return TCL_ERROR;
278 }
279 if (StyleConfigure(interp, stylePtr, argc-2, argv+2, 0) != TCL_OK) {
280 DeleteStyle(stylePtr);
281 return TCL_ERROR;
282 }
283 Tk_CreateEventHandler(tkwin, StructureNotifyMask,
284 RefWindowStructureProc, (ClientData)stylePtr);
285
286 Tcl_ResetResult(interp);
287 Tcl_SetObjResult(interp, LangObjectObj( interp, styleName));
288 return TCL_OK;
289 }
290
291 static int
StyleCmd(clientData,interp,argc,argv)292 StyleCmd(clientData, interp, argc, argv)
293 ClientData clientData;
294 Tcl_Interp *interp;
295 int argc;
296 char **argv;
297 {
298 int code;
299
300 static Tix_SubCmdInfo subCmdInfo[] = {
301 {TIX_DEFAULT_LEN, "cget", 1, 1, StyleCGetCmd,
302 "option"},
303 {TIX_DEFAULT_LEN, "configure", 0, TIX_VAR_ARGS, StyleConfigCmd,
304 "?option? ?value? ?option value ... ?"},
305 {TIX_DEFAULT_LEN, "delete", 0, 0, StyleDeleteCmd,
306 ""},
307 };
308
309 static Tix_CmdInfo cmdInfo = {
310 Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? arg ?arg ...?",
311 };
312
313 Tcl_Preserve(clientData);
314 code = Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
315 interp, argc, argv);
316 Tcl_Release(clientData);
317
318 return code;
319 }
320
321 /*----------------------------------------------------------------------
322 * "cget" sub command
323 *----------------------------------------------------------------------
324 */
325 static int
StyleCGetCmd(clientData,interp,argc,argv)326 StyleCGetCmd(clientData, interp, argc, argv)
327 ClientData clientData;
328 Tcl_Interp *interp; /* Current interpreter. */
329 int argc; /* Number of arguments. */
330 char **argv; /* Argument strings. */
331 {
332 Tix_DItemStyle* stylePtr= (Tix_DItemStyle*) clientData;
333
334 return Tk_ConfigureValue(interp, stylePtr->base.tkwin,
335 stylePtr->base.diTypePtr->styleConfigSpecs,
336 (char *)stylePtr, argv[0], 0);
337 }
338
339 /*----------------------------------------------------------------------
340 * "configure" sub command
341 *----------------------------------------------------------------------
342 */
343 static int
StyleConfigCmd(clientData,interp,argc,argv)344 StyleConfigCmd(clientData, interp, argc, argv)
345 ClientData clientData;
346 Tcl_Interp *interp; /* Current interpreter. */
347 int argc; /* Number of arguments. */
348 char **argv; /* Argument strings. */
349 {
350 Tix_DItemStyle* stylePtr= (Tix_DItemStyle*) clientData;
351
352 if (argc == 0) {
353 return Tk_ConfigureInfo(interp, stylePtr->base.tkwin,
354 stylePtr->base.diTypePtr->styleConfigSpecs,
355 (char *)stylePtr, (char *) NULL, 0);
356 } else if (argc == 1) {
357 return Tk_ConfigureInfo(interp, stylePtr->base.tkwin,
358 stylePtr->base.diTypePtr->styleConfigSpecs,
359 (char *)stylePtr, argv[0], 0);
360 } else {
361 return StyleConfigure(interp, stylePtr, argc, argv,
362 TK_CONFIG_ARGV_ONLY);
363 }
364 }
365
366 /*----------------------------------------------------------------------
367 * "delete" sub command
368 *----------------------------------------------------------------------
369 */
370 static int
StyleDeleteCmd(clientData,interp,argc,argv)371 StyleDeleteCmd(clientData, interp, argc, argv)
372 ClientData clientData;
373 Tcl_Interp *interp; /* Current interpreter. */
374 int argc; /* Number of arguments. */
375 char **argv; /* Argument strings. */
376 {
377 Tix_DItemStyle* stylePtr= (Tix_DItemStyle*) clientData;
378
379 if (stylePtr->base.flags & TIX_STYLE_DEFAULT) {
380 Tcl_AppendResult(interp, "Cannot delete default item style",
381 NULL);
382 return TCL_ERROR;
383 }
384
385 DeleteStyle(stylePtr);
386 return TCL_OK;
387 }
388
389 static int
StyleConfigure(interp,stylePtr,argc,argv,flags)390 StyleConfigure(interp, stylePtr, argc, argv, flags)
391 Tcl_Interp *interp; /* Used for error reporting. */
392 Tix_DItemStyle* stylePtr; /* Information about the style; may or may
393 * not already have values for some fields. */
394 int argc; /* Number of valid entries in argv. */
395 char **argv; /* Arguments. */
396 int flags; /* Flags to pass to Tk_ConfigureWidget. */
397 {
398 Tix_DItemInfo * diTypePtr = stylePtr->base.diTypePtr;
399
400 if (diTypePtr->styleConfigureProc(stylePtr, argc, argv, flags) != TCL_OK) {
401 return TCL_ERROR;
402 }
403 return TCL_OK;
404 }
405
406 /*----------------------------------------------------------------------
407 * StyleDestroy --
408 *
409 * Destroy a display style.
410 *----------------------------------------------------------------------
411 */
412 static void
StyleDestroy(clientData)413 StyleDestroy(clientData)
414 char *clientData;
415 {
416 Tix_DItemStyle* stylePtr= (Tix_DItemStyle*) clientData;
417
418 if ((stylePtr->base.flags & TIX_STYLE_DEFAULT)) {
419 /*
420 * If this is the default style for the display items, we
421 * can't tell the display items that it has lost its style,
422 * otherwise the ditem will just attempt to create the default
423 * style again, and we will go into an infinite loop
424 */
425 if (stylePtr->base.refCount != 0) {
426 /*
427 * If the refcount is not zero, this style will NOT be
428 * destroyed. The real destroy will be triggered if all
429 * DItems associated with this style is destroyed (in the
430 * ListDelete() function).
431 *
432 * If a widget is destroyed, it is the responsibility of the
433 * widget writer to delete all DItems associated with this
434 * widget. We can discover memory leak if the widget is
435 * destroyed but some default styles associated with it still
436 * exist
437 */
438 return;
439 }
440 } else {
441 stylePtr->base.refCount = 0;
442 }
443
444 Tcl_DeleteHashTable(&stylePtr->base.items);
445 ckfree((char*)stylePtr->base.name);
446 stylePtr->base.diTypePtr->styleFreeProc(stylePtr);
447 }
448
449 static void
StyleCmdDeletedProc(clientData)450 StyleCmdDeletedProc(clientData)
451 ClientData clientData;
452 {
453 Tix_DItemStyle * stylePtr = (Tix_DItemStyle *)clientData;
454
455 stylePtr->base.styleCmd = NULL;
456 if (stylePtr->base.flags & TIX_STYLE_DEFAULT) {
457 /*
458 * Don't do anything
459 * ToDo: maybe should give a background warning:
460 */
461 } else {
462 DeleteStyle(stylePtr);
463 }
464 }
465
466 static void
DeleteStyle(stylePtr)467 DeleteStyle(stylePtr)
468 Tix_DItemStyle * stylePtr;
469 {
470 Tcl_HashEntry * hashPtr;
471
472 if (!(stylePtr->base.flags & TIX_STYLE_DELETED)) {
473 stylePtr->base.flags |= TIX_STYLE_DELETED;
474
475 if (stylePtr->base.styleCmd != NULL) {
476 Tcl_DeleteCommand(stylePtr->base.interp,
477 Tcl_GetCommandName(stylePtr->base.interp,
478 stylePtr->base.styleCmd));
479 }
480 hashPtr=Tcl_FindHashEntry(GetStyleTable(stylePtr->base.interp), stylePtr->base.name);
481 if (hashPtr != NULL) {
482 Tcl_DeleteHashEntry(hashPtr);
483 }
484 ListDeleteAll(stylePtr);
485
486 Tcl_EventuallyFree((ClientData)stylePtr, StyleDestroy);
487 }
488 }
489
490 /*
491 *----------------------------------------------------------------------
492 * FindDefaultStyle --
493 *
494 * Return the default style of the given type of ditem for the
495 * given tkwin, if such a default style exists.
496 *
497 * Results:
498 * Pointer to the default style or NULL.
499 *
500 * Side effects:
501 * None.
502 *----------------------------------------------------------------------
503 */
504
505 static Tix_DItemStyle*
FindDefaultStyle(interp,diTypePtr,tkwin)506 FindDefaultStyle(interp, diTypePtr, tkwin)
507 Tcl_Interp *interp;
508 Tix_DItemInfo * diTypePtr;
509 Tk_Window tkwin;
510 {
511 Tcl_HashEntry *hashPtr;
512 StyleInfo * infoPtr;
513 StyleLink * linkPtr;
514
515 if ((hashPtr=Tcl_FindHashEntry(GetDefaultTable(interp), (char*)tkwin)) == NULL) {
516 return NULL;
517 }
518 infoPtr = (StyleInfo *)Tcl_GetHashValue(hashPtr);
519 for (linkPtr = infoPtr->linkHead; linkPtr; linkPtr=linkPtr->next) {
520 if (linkPtr->diTypePtr == diTypePtr) {
521 return linkPtr->stylePtr;
522 }
523 }
524 return NULL;
525 }
526
SetDefaultStyle(diTypePtr,tkwin,stylePtr)527 static void SetDefaultStyle(diTypePtr, tkwin, stylePtr)
528 Tix_DItemInfo * diTypePtr;
529 Tk_Window tkwin;
530 Tix_DItemStyle * stylePtr;
531 {
532 Tcl_HashEntry *hashPtr;
533 StyleInfo * infoPtr;
534 StyleLink * newPtr;
535 int isNew;
536
537 newPtr = (StyleLink *)ckalloc(sizeof(StyleLink));
538 newPtr->diTypePtr = diTypePtr;
539 newPtr->stylePtr = stylePtr;
540
541 hashPtr = Tcl_CreateHashEntry(GetDefaultTable(stylePtr->base.interp), (char*)tkwin, &isNew);
542
543 if (!isNew) {
544 infoPtr = (StyleInfo *)Tcl_GetHashValue(hashPtr);
545 if (infoPtr->tmplPtr) {
546 if (diTypePtr->styleSetTemplateProc != NULL) {
547 diTypePtr->styleSetTemplateProc(stylePtr,
548 infoPtr->tmplPtr);
549 }
550 }
551 } else {
552 infoPtr = (StyleInfo *)ckalloc(sizeof(StyleInfo));
553 infoPtr->linkHead = NULL;
554 infoPtr->tmplPtr = NULL;
555
556 Tk_CreateEventHandler(tkwin, StructureNotifyMask,
557 DefWindowStructureProc, (ClientData)tkwin);
558 Tcl_SetHashValue(hashPtr, (char*)infoPtr);
559 }
560 newPtr->next = infoPtr->linkHead;
561 infoPtr->linkHead = newPtr;
562 }
563
564 /*
565 *----------------------------------------------------------------------
566 * TixGetDefaultDItemStyle --
567 *
568 * Gets the default style for an item if the application doesn't
569 * explicitly give it an style with the -style switch.
570 *
571 * Results:
572 * The default style.
573 *
574 * Side effects:
575 *
576 *----------------------------------------------------------------------
577 */
578
579 Tix_DItemStyle*
TixGetDefaultDItemStyle(ddPtr,diTypePtr,iPtr,oldStylePtr)580 TixGetDefaultDItemStyle(ddPtr, diTypePtr, iPtr, oldStylePtr)
581 Tix_DispData * ddPtr; /* Info about the display. */
582 Tix_DItemInfo * diTypePtr; /* Info about the DItem type. */
583 Tix_DItem *iPtr; /* Get default style for this DItem. */
584 Tix_DItemStyle* oldStylePtr; /* ?? */
585 {
586 Tcl_DString dString;
587 Tix_DItemStyle* stylePtr;
588 int isNew;
589
590 stylePtr = FindDefaultStyle(ddPtr->interp, diTypePtr, ddPtr->tkwin);
591 if (stylePtr == NULL) {
592 /*
593 * Format default name for this style+window
594 */
595 Tcl_DStringInit(&dString);
596 Tcl_DStringAppend(&dString, "style", 5);
597 if (ddPtr->tkwin) {
598 Tcl_DStringAppend(&dString, Tk_PathName(ddPtr->tkwin),
599 strlen(Tk_PathName(ddPtr->tkwin)));
600 }
601 Tcl_DStringAppend(&dString, ":", 1);
602 Tcl_DStringAppend(&dString, diTypePtr->name, strlen(diTypePtr->name));
603
604 /*
605 * Create the new style
606 */
607 stylePtr = GetDItemStyle(ddPtr, diTypePtr, Tcl_DStringValue(&dString), &isNew);
608 if (isNew) {
609 diTypePtr->styleConfigureProc(stylePtr, 0, NULL, 0);
610 stylePtr->base.flags |= TIX_STYLE_DEFAULT;
611 }
612
613 SetDefaultStyle(diTypePtr, ddPtr->tkwin, stylePtr);
614 Tcl_DStringFree(&dString);
615 }
616
617 if (oldStylePtr) {
618 ListDelete(oldStylePtr, iPtr);
619 }
620 if (stylePtr) {
621 ListAdd(stylePtr, iPtr);
622 }
623
624 return stylePtr;
625 }
626
Tix_SetDefaultStyleTemplate(tkwin,tmplPtr)627 void Tix_SetDefaultStyleTemplate(tkwin, tmplPtr)
628 Tk_Window tkwin;
629 Tix_StyleTemplate * tmplPtr;
630 {
631 TkWindow *winPtr = (TkWindow *) tkwin;
632 Tcl_Interp *interp = winPtr->mainPtr->interp;
633 Tcl_HashEntry * hashPtr;
634 StyleInfo * infoPtr;
635 StyleLink * linkPtr;
636 int isNew;
637
638 hashPtr=Tcl_CreateHashEntry(GetDefaultTable(interp), (char*)tkwin, &isNew);
639 if (!isNew) {
640 infoPtr = (StyleInfo *)Tcl_GetHashValue(hashPtr);
641 infoPtr->tmplPtr = &infoPtr->tmpl;
642 infoPtr->tmpl = *tmplPtr;
643
644 for (linkPtr = infoPtr->linkHead; linkPtr; linkPtr=linkPtr->next) {
645 if (linkPtr->diTypePtr->styleSetTemplateProc != NULL) {
646 linkPtr->diTypePtr->styleSetTemplateProc(linkPtr->stylePtr,
647 tmplPtr);
648 }
649 }
650 } else {
651 infoPtr = (StyleInfo *)ckalloc(sizeof(StyleInfo));
652 infoPtr->linkHead = NULL;
653 infoPtr->tmplPtr = &infoPtr->tmpl;
654 infoPtr->tmpl = *tmplPtr;
655
656 Tk_CreateEventHandler(tkwin, StructureNotifyMask,
657 DefWindowStructureProc, (ClientData)tkwin);
658 Tcl_SetHashValue(hashPtr, (char*)infoPtr);
659 }
660 }
661
662 /*
663 *----------------------------------------------------------------------
664 * GetDItemStyle --
665 *
666 * Returns an ItemStyle with the given name.
667 *
668 * Results:
669 * Pointer to the given Tix_DItsmStyle.
670 *
671 * Side effects:
672 * If the style doesn't already exist, it is allocated.
673 *----------------------------------------------------------------------
674 */
675
676 static Tix_DItemStyle*
GetDItemStyle(ddPtr,diTypePtr,styleName,isNew_ret)677 GetDItemStyle(ddPtr, diTypePtr, styleName, isNew_ret)
678 Tix_DispData * ddPtr;
679 Tix_DItemInfo * diTypePtr;
680 char * styleName;
681 int * isNew_ret;
682 {
683 Tcl_HashEntry *hashPtr;
684 int isNew;
685 Tix_DItemStyle * stylePtr;
686
687 if (tableInited == 0) {
688 InitHashTables();
689 }
690
691 hashPtr = Tcl_CreateHashEntry(GetStyleTable(ddPtr->interp), styleName, &isNew);
692 if (!isNew) {
693 stylePtr = (Tix_DItemStyle *)Tcl_GetHashValue(hashPtr);
694 }
695 else {
696 stylePtr = diTypePtr->styleCreateProc(ddPtr->interp,
697 ddPtr->tkwin, diTypePtr, styleName);
698 stylePtr->base.styleCmd = Lang_CreateObject(ddPtr->interp,
699 styleName, StyleCmd, (ClientData)stylePtr, StyleCmdDeletedProc);
700 stylePtr->base.interp = ddPtr->interp;
701 stylePtr->base.tkwin = ddPtr->tkwin;
702 stylePtr->base.diTypePtr = diTypePtr;
703 stylePtr->base.name = tixStrDup(styleName);
704 stylePtr->base.pad[0] = 0;
705 stylePtr->base.pad[1] = 0;
706 stylePtr->base.anchor = TK_ANCHOR_CENTER;
707 stylePtr->base.refCount = 0;
708 stylePtr->base.flags = 0;
709 Tcl_InitHashTable(&stylePtr->base.items, TCL_ONE_WORD_KEYS);
710
711 Tcl_SetHashValue(hashPtr, (char*)stylePtr);
712 }
713
714 if (isNew_ret != NULL) {
715 * isNew_ret = isNew;
716 }
717 return stylePtr;
718 }
719
FindStyle(styleName,interp)720 static Tix_DItemStyle* FindStyle(styleName, interp)
721 char *styleName;
722 Tcl_Interp *interp; /* Current interpreter. */
723 {
724 Tcl_HashEntry *hashPtr;
725
726 if (tableInited == 0) {
727 InitHashTables();
728 }
729 if ((hashPtr=Tcl_FindHashEntry(GetStyleTable(interp), styleName)) == NULL) {
730 return NULL;
731 }
732
733 return (Tix_DItemStyle *)Tcl_GetHashValue(hashPtr);
734 }
735
736 /*----------------------------------------------------------------------
737 * TixDItemStyleChanged --
738 *
739 * Tell each Ditem that are affected by this style that the style
740 * has changed. The Ditems will respond by updating their
741 * attributes according to the new values of the style.
742 *----------------------------------------------------------------------
743 */
744
TixDItemStyleChanged(diTypePtr,stylePtr)745 void TixDItemStyleChanged(diTypePtr, stylePtr)
746 Tix_DItemInfo * diTypePtr;
747 Tix_DItemStyle * stylePtr;
748 {
749 Tcl_HashSearch hashSearch;
750 Tcl_HashEntry *hashPtr;
751 Tix_DItem * iPtr;
752
753 for (hashPtr = Tcl_FirstHashEntry(&stylePtr->base.items, &hashSearch);
754 hashPtr;
755 hashPtr = Tcl_NextHashEntry(&hashSearch)) {
756
757 iPtr = (Tix_DItem *)Tcl_GetHashValue(hashPtr);
758 diTypePtr->styleChangedProc(iPtr);
759 }
760 }
761
762 /*----------------------------------------------------------------------
763 * ListAdd --
764 *
765 * Add an item to the list of items affected by a style.
766 *----------------------------------------------------------------------
767 */
768
769 static void
ListAdd(stylePtr,iPtr)770 ListAdd(stylePtr, iPtr)
771 Tix_DItemStyle * stylePtr;
772 Tix_DItem *iPtr;
773 {
774 Tcl_HashEntry *hashPtr;
775 int isNew;
776
777 hashPtr = Tcl_CreateHashEntry(&stylePtr->base.items, (char*)iPtr, &isNew);
778 if (!isNew) {
779 panic("DItem is already associated with style");
780 } else {
781 Tcl_SetHashValue(hashPtr, (char*)iPtr);
782 }
783 ++ stylePtr->base.refCount;
784 }
785
786 static void
ListDelete(stylePtr,iPtr)787 ListDelete(stylePtr, iPtr)
788 Tix_DItemStyle * stylePtr;
789 Tix_DItem *iPtr;
790 {
791 Tcl_HashEntry *hashPtr;
792
793 hashPtr = Tcl_FindHashEntry(&stylePtr->base.items, (char*)iPtr);
794 if (hashPtr == NULL) {
795 panic("DItem is not associated with style");
796 }
797 Tcl_DeleteHashEntry(hashPtr);
798 stylePtr->base.refCount--;
799
800 if ((stylePtr->base.refCount == 0) &&
801 (stylePtr->base.flags & TIX_STYLE_DELETED) &&
802 (stylePtr->base.flags & TIX_STYLE_DEFAULT)) {
803 Tcl_EventuallyFree((ClientData)stylePtr, (Tix_FreeProc *)StyleDestroy);
804 }
805 }
806
807 static void
ListDeleteAll(stylePtr)808 ListDeleteAll(stylePtr)
809 Tix_DItemStyle * stylePtr;
810 {
811 Tcl_HashSearch hashSearch;
812 Tcl_HashEntry *hashPtr;
813 Tix_DItem * iPtr;
814
815 for (hashPtr = Tcl_FirstHashEntry(&stylePtr->base.items, &hashSearch);
816 hashPtr;
817 hashPtr = Tcl_NextHashEntry(&hashSearch)) {
818
819 iPtr = (Tix_DItem *)Tcl_GetHashValue(hashPtr);
820 if (stylePtr->base.diTypePtr->lostStyleProc != NULL) {
821 stylePtr->base.diTypePtr->lostStyleProc(iPtr);
822 }
823 Tcl_DeleteHashEntry(hashPtr);
824 }
825 }
826 /*
827 *--------------------------------------------------------------
828 *
829 * DefWindowStructureProc --
830 *
831 * This procedure is invoked whenever StructureNotify events
832 * occur for a window that has some default style(s) associated with it
833 *
834 * Results:
835 * None.
836 *
837 * Side effects:
838 * The style(s) associated with this window will all be deleted.
839 *
840 *--------------------------------------------------------------
841 */
842
843 static void
DefWindowStructureProc(clientData,eventPtr)844 DefWindowStructureProc(clientData, eventPtr)
845 ClientData clientData; /* Pointer to record describing window item. */
846 XEvent *eventPtr; /* Describes what just happened. */
847 {
848 Tk_Window tkwin = (Tk_Window)clientData;
849 TkWindow *winPtr = (TkWindow *) tkwin;
850 Tcl_Interp *interp = winPtr->mainPtr->interp;
851 Tcl_HashEntry *hashPtr;
852 StyleInfo * infoPtr;
853 StyleLink * linkPtr, *toFree;
854
855 if (eventPtr->type != DestroyNotify) {
856 return;
857 }
858 if ((hashPtr=Tcl_FindHashEntry(GetDefaultTable(interp), (char*)tkwin)) == NULL) {
859 return;
860 }
861 infoPtr = (StyleInfo *)Tcl_GetHashValue(hashPtr);
862 for (linkPtr = infoPtr->linkHead; linkPtr; ) {
863 toFree = linkPtr;
864 linkPtr=linkPtr->next;
865
866 DeleteStyle(toFree->stylePtr);
867 ckfree((char*)toFree);
868 }
869
870 ckfree((char*)infoPtr);
871 Tcl_DeleteHashEntry(hashPtr);
872 }
873
874 /*
875 *--------------------------------------------------------------
876 *
877 * RefWindowStructureProc --
878 *
879 * This procedure is invoked when the refwindow of a non-default
880 * style is deleted.
881 *
882 * Results:
883 * None.
884 *
885 * Side effects:
886 * The style is deleted.
887 *
888 *--------------------------------------------------------------
889 */
890
891 static void
RefWindowStructureProc(clientData,eventPtr)892 RefWindowStructureProc(clientData, eventPtr)
893 ClientData clientData; /* Pointer to record describing window item. */
894 XEvent *eventPtr; /* Describes what just happened. */
895 {
896 Tix_DItemStyle * stylePtr = (Tix_DItemStyle *)clientData;
897
898 if (eventPtr->type == DestroyNotify) {
899 /*
900 * If some DItems are still associated with this window, they
901 * will receive a "LostStyle" notification.
902 */
903 DeleteStyle(stylePtr);
904 }
905 }
906
907 /*----------------------------------------------------------------------
908 *
909 * The Tix Customed Config Options
910 *
911 *----------------------------------------------------------------------
912 */
913
914 /*
915 * The global data structures to use in widget configSpecs arrays
916 *
917 * These are declared in <tix.h>
918 */
919
920 #ifndef _LANG
921 Tk_CustomOption tixConfigItemStyle = {
922 DItemStyleParseProc, DItemStylePrintProc, 0,
923 };
924 #endif
925
926 /*----------------------------------------------------------------------
927 * DItemStyleParseProc --
928 *
929 * Parse the text string and store the Tix_DItemStyleType information
930 * inside the widget record.
931 *----------------------------------------------------------------------
932 */
DItemStyleParseProc(clientData,interp,tkwin,value,widRec,offset)933 LINKAGE int DItemStyleParseProc(clientData, interp, tkwin, value, widRec,offset)
934 ClientData clientData;
935 Tcl_Interp *interp;
936 Tk_Window tkwin;
937 Tcl_Obj * value;
938 char *widRec; /* Must point to a valid Tix_DItem struct */
939 int offset;
940 {
941 Tix_DItem * iPtr = (Tix_DItem *)widRec;
942 Tix_DItemStyle ** ptr = (Tix_DItemStyle **)(widRec + offset);
943 Tix_DItemStyle * oldPtr = *ptr;
944 Tix_DItemStyle * newPtr;
945
946 if (value == NULL || strlen(Tcl_GetString(value)) == 0) {
947 /*
948 * User gives a NULL string -- meaning he wants the default
949 * style
950 */
951 if (oldPtr && oldPtr->base.flags & TIX_STYLE_DEFAULT) {
952 /*
953 * This ditem is already associated with a default style. Let's
954 * keep it.
955 */
956 newPtr = oldPtr;
957 } else {
958 if (oldPtr) {
959 ListDelete(oldPtr, iPtr);
960 }
961 newPtr = NULL;
962 }
963 } else {
964 if ((newPtr = FindStyle(Tcl_GetString(value), interp)) == NULL) {
965 goto not_found;
966 }
967 if (newPtr->base.flags & TIX_STYLE_DELETED) {
968 goto not_found;
969 }
970 if (newPtr->base.diTypePtr != iPtr->base.diTypePtr) {
971 Tcl_AppendResult(interp, "Style type mismatch ",
972 "Needed ", iPtr->base.diTypePtr->name, " style but got ",
973 newPtr->base.diTypePtr->name, " style", NULL);
974 return TCL_ERROR;
975 }
976 if (oldPtr != newPtr) {
977 if (oldPtr != NULL) {
978 ListDelete(oldPtr, iPtr);
979 }
980 ListAdd(newPtr, iPtr);
981 }
982 }
983
984 *ptr = newPtr;
985 return TCL_OK;
986
987 not_found:
988 Tcl_AppendResult(interp, "Display style \"", Tcl_GetString(value),
989 "\" not found", NULL);
990 return TCL_ERROR;
991 }
992
993 LINKAGE Tcl_Obj *
DItemStylePrintProc(clientData,tkwin,widRec,offset,freeProcPtr)994 DItemStylePrintProc(clientData, tkwin, widRec,offset, freeProcPtr)
995 ClientData clientData;
996 Tk_Window tkwin;
997 char *widRec;
998 int offset;
999 Tcl_FreeProc **freeProcPtr;
1000 {
1001 Tix_DItemStyle *stylePtr = *((Tix_DItemStyle**)(widRec+offset));
1002 Tcl_Obj * result = NULL;
1003 if (stylePtr != NULL && !(stylePtr->base.flags & TIX_STYLE_DEFAULT)) {
1004 LangSetObj(&result,LangObjectObj(stylePtr->base.interp,
1005 stylePtr->base.name));
1006 }
1007 return result;
1008 }
1009
1010
1011