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