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