1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/*
* 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.
*
* RCS: @(#) $Id: tkMacWinMenu.c,v 1.3 1999/04/16 01:51:19 stanton Exp $
*/
#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);
}
|