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