/* 
 * tkMacWinMenu.c --
 *
 *	This module implements the common elements of the Mac and Windows
 *	specific features of menus. This file is not used for UNIX.
 *
 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMenu.h"

typedef struct ThreadSpecificData {
    int postCommandGeneration;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;


static int			PreprocessMenu _ANSI_ARGS_((TkMenu *menuPtr));


/*
 *----------------------------------------------------------------------
 *
 * PreprocessMenu --
 *
 *	The guts of the preprocessing. Recursive.
 *
 * Results:
 *	The return value is a standard Tcl result (errors can occur
 *	while the postcommands are being processed).
 *
 * Side effects:
 *	Since commands can get executed while this routine is being executed,
 *	the entire world can change.
 *
 *----------------------------------------------------------------------
 */

static int
PreprocessMenu(menuPtr)
    TkMenu *menuPtr;
{
    int index, result, finished;
    TkMenu *cascadeMenuPtr;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
   
    Tcl_Preserve((ClientData) menuPtr);
    
    /*
     * First, let's process the post command on ourselves. If this command
     * destroys this menu, or if there was an error, we are done.
     */
     
    result = TkPostCommand(menuPtr);
    if ((result != TCL_OK) || (menuPtr->tkwin == NULL)) {
    	goto done;
    }
    
    /*
     * Now, we go through structure and process all of the commands.
     * Since the structure is changing, we stop after we do one command,
     * and start over. When we get through without doing any, we are done.
     */
    
    
    do {
    	finished = 1;
        for (index = 0; index < menuPtr->numEntries; index++) {
            if ((menuPtr->entries[index]->type == CASCADE_ENTRY)
            	    && (menuPtr->entries[index]->namePtr != NULL)) {
            	if ((menuPtr->entries[index]->childMenuRefPtr != NULL)
            		&& (menuPtr->entries[index]->childMenuRefPtr->menuPtr
            		!= NULL)) {
            	    cascadeMenuPtr =
            	    	    menuPtr->entries[index]->childMenuRefPtr->menuPtr;
            	    if (cascadeMenuPtr->postCommandGeneration != 
            	    	    tsdPtr->postCommandGeneration) {
            	    	cascadeMenuPtr->postCommandGeneration = 
            	    		tsdPtr->postCommandGeneration;
            	        result = PreprocessMenu(cascadeMenuPtr);
            	        if (result != TCL_OK) {
            	            goto done;
            	        }
            	        finished = 0;
            	        break;
            	    }
            	}
            }
        }
    } while (!finished);
    
    done:
    Tcl_Release((ClientData)menuPtr);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TkPreprocessMenu --
 *
 *	On the Mac and on Windows, all of the postcommand processing has
 *	to be done on the entire tree underneath the main window to be
 *	posted. This means that we have to traverse the menu tree and
 *	issue the postcommands for all of the menus that have cascades
 *	attached. Since the postcommands can change the menu structure while
 *	we are traversing, we have to be extremely careful. Basically, the
 *	idea is to traverse the structure until we succesfully process
 *	one postcommand. Then we start over, and do it again until
 *	we traverse the whole structure without processing any postcommands.
 *
 *	We are also going to set up the cascade back pointers in here
 *	since we have to traverse the entire structure underneath the menu
 *	anyway, We can clear the postcommand marks while we do that.
 *
 * Results:
 *	The return value is a standard Tcl result (errors can occur
 *	while the postcommands are being processed).
 *
 * Side effects:
 *	Since commands can get executed while this routine is being executed,
 *	the entire world can change.
 *
 *----------------------------------------------------------------------
 */

int
TkPreprocessMenu(menuPtr)
    TkMenu *menuPtr;
{
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    tsdPtr->postCommandGeneration++;
    menuPtr->postCommandGeneration = tsdPtr->postCommandGeneration;
    return PreprocessMenu(menuPtr);
}
