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