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