1/*
2 * tkMacWinMenu.c --
3 *
4 *	This module implements the common elements of the Mac and Windows
5 *	specific features of menus. This file is not used for UNIX.
6 *
7 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id$
13 */
14
15#include "tkInt.h"
16#include "tkMenu.h"
17
18typedef struct ThreadSpecificData {
19    int postCommandGeneration;
20} ThreadSpecificData;
21static Tcl_ThreadDataKey dataKey;
22
23static int		PreprocessMenu(TkMenu *menuPtr);
24
25/*
26 *----------------------------------------------------------------------
27 *
28 * PreprocessMenu --
29 *
30 *	The guts of the preprocessing. Recursive.
31 *
32 * Results:
33 *	The return value is a standard Tcl result (errors can occur while the
34 *	postcommands are being processed).
35 *
36 * Side effects:
37 *	Since commands can get executed while this routine is being executed,
38 *	the entire world can change.
39 *
40 *----------------------------------------------------------------------
41 */
42
43static int
44PreprocessMenu(
45    TkMenu *menuPtr)
46{
47    int index, result, finished;
48    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
49	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
50
51    Tcl_Preserve((ClientData) menuPtr);
52
53    /*
54     * First, let's process the post command on ourselves. If this command
55     * destroys this menu, or if there was an error, we are done.
56     */
57
58    result = TkPostCommand(menuPtr);
59    if ((result != TCL_OK) || (menuPtr->tkwin == NULL)) {
60	goto done;
61    }
62
63    /*
64     * Now, we go through structure and process all of the commands. Since the
65     * structure is changing, we stop after we do one command, and start over.
66     * When we get through without doing any, we are done.
67     */
68
69    do {
70	finished = 1;
71	for (index = 0; index < menuPtr->numEntries; index++) {
72	    register TkMenuEntry *entryPtr = menuPtr->entries[index];
73
74	    if ((entryPtr->type == CASCADE_ENTRY)
75		    && (entryPtr->namePtr != NULL)
76		    && (entryPtr->childMenuRefPtr != NULL)
77		    && (entryPtr->childMenuRefPtr->menuPtr != NULL)) {
78		TkMenu *cascadeMenuPtr = entryPtr->childMenuRefPtr->menuPtr;
79
80		if (cascadeMenuPtr->postCommandGeneration !=
81			tsdPtr->postCommandGeneration) {
82		    cascadeMenuPtr->postCommandGeneration =
83			    tsdPtr->postCommandGeneration;
84		    result = PreprocessMenu(cascadeMenuPtr);
85		    if (result != TCL_OK) {
86			goto done;
87		    }
88		    finished = 0;
89		    break;
90		}
91	    }
92	}
93    } while (!finished);
94
95  done:
96    Tcl_Release((ClientData) menuPtr);
97    return result;
98}
99
100/*
101 *----------------------------------------------------------------------
102 *
103 * TkPreprocessMenu --
104 *
105 *	On the Mac and on Windows, all of the postcommand processing has to be
106 *	done on the entire tree underneath the main window to be posted. This
107 *	means that we have to traverse the menu tree and issue the
108 *	postcommands for all of the menus that have cascades attached. Since
109 *	the postcommands can change the menu structure while we are
110 *	traversing, we have to be extremely careful. Basically, the idea is to
111 *	traverse the structure until we succesfully process one postcommand.
112 *	Then we start over, and do it again until we traverse the whole
113 *	structure without processing any postcommands.
114 *
115 *	We are also going to set up the cascade back pointers in here since we
116 *	have to traverse the entire structure underneath the menu anyway. We
117 *	can clear the postcommand marks while we do that.
118 *
119 * Results:
120 *	The return value is a standard Tcl result (errors can occur while the
121 *	postcommands are being processed).
122 *
123 * Side effects:
124 *	Since commands can get executed while this routine is being executed,
125 *	the entire world can change.
126 *
127 *----------------------------------------------------------------------
128 */
129
130int
131TkPreprocessMenu(
132    TkMenu *menuPtr)
133{
134    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
135	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
136
137    tsdPtr->postCommandGeneration++;
138    menuPtr->postCommandGeneration = tsdPtr->postCommandGeneration;
139    return PreprocessMenu(menuPtr);
140}
141
142/*
143 * Local Variables:
144 * mode: c
145 * c-basic-offset: 4
146 * fill-column: 78
147 * End:
148 */
149