/* * 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 "tkInt.h" #include "tkMenu.h" typedef struct ThreadSpecificData { int postCommandGeneration; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; static int PreprocessMenu(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( TkMenu *menuPtr) { int index, result, finished; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); Tcl_Preserve(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++) { register TkMenuEntry *entryPtr = menuPtr->entries[index]; if ((entryPtr->type == CASCADE_ENTRY) && (entryPtr->namePtr != NULL) && (entryPtr->childMenuRefPtr != NULL) && (entryPtr->childMenuRefPtr->menuPtr != NULL)) { TkMenu *cascadeMenuPtr = entryPtr->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(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( TkMenu *menuPtr) { ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); tsdPtr->postCommandGeneration++; menuPtr->postCommandGeneration = tsdPtr->postCommandGeneration; return PreprocessMenu(menuPtr); } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */