📄 tkmenu.c
字号:
Tcl_UntraceVar(menuPtr->interp, mePtr->name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, (ClientData) mePtr); } TkpDestroyMenuEntry(mePtr); TkMenuEntryFreeDrawOptions(mePtr); Tk_FreeOptions(tkMenuEntryConfigSpecs, (char *) mePtr, menuPtr->display, (COMMAND_MASK << mePtr->type)); ckfree((char *) mePtr);}/* *--------------------------------------------------------------------------- * * MenuWorldChanged -- * * This procedure is called when the world has changed in some * way (such as the fonts in the system changing) and the widget needs * to recompute all its graphics contexts and determine its new geometry. * * Results: * None. * * Side effects: * Menu will be relayed out and redisplayed. * *--------------------------------------------------------------------------- */ static voidMenuWorldChanged(instanceData) ClientData instanceData; /* Information about widget. */{ TkMenu *menuPtr = (TkMenu *) instanceData; int i; TkMenuConfigureDrawOptions(menuPtr); for (i = 0; i < menuPtr->numEntries; i++) { TkMenuConfigureEntryDrawOptions(menuPtr->entries[i], menuPtr->entries[i]->index); TkpConfigureMenuEntry(menuPtr->entries[i]); }}/* *---------------------------------------------------------------------- * * ConfigureMenu -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or * reconfigure) a menu widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as colors, font, etc. get set * for menuPtr; old resources get freed, if there were any. * *---------------------------------------------------------------------- */static intConfigureMenu(interp, menuPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register TkMenu *menuPtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */{ int i; TkMenu* menuListPtr; for (menuListPtr = menuPtr->masterMenuPtr; menuListPtr != NULL; menuListPtr = menuListPtr->nextInstancePtr) { if (Tk_ConfigureWidget(interp, menuListPtr->tkwin, tkMenuConfigSpecs, argc, argv, (char *) menuListPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * When a menu is created, the type is in all of the arguments * to the menu command. Let Tk_ConfigureWidget take care of * parsing them, and then set the type after we can look at * the type string. Once set, a menu's type cannot be changed */ if (menuListPtr->menuType == UNKNOWN_TYPE) { if (strcmp(menuListPtr->menuTypeName, "menubar") == 0) { menuListPtr->menuType = MENUBAR; } else if (strcmp(menuListPtr->menuTypeName, "tearoff") == 0) { menuListPtr->menuType = TEAROFF_MENU; } else { menuListPtr->menuType = MASTER_MENU; } } /* * Depending on the -tearOff option, make sure that there is or * isn't an initial tear-off entry at the beginning of the menu. */ if (menuListPtr->tearOff) { if ((menuListPtr->numEntries == 0) || (menuListPtr->entries[0]->type != TEAROFF_ENTRY)) { if (MenuNewEntry(menuListPtr, 0, TEAROFF_ENTRY) == NULL) { return TCL_ERROR; } } } else if ((menuListPtr->numEntries > 0) && (menuListPtr->entries[0]->type == TEAROFF_ENTRY)) { int i; Tcl_EventuallyFree((ClientData) menuListPtr->entries[0], DestroyMenuEntry); for (i = 0; i < menuListPtr->numEntries - 1; i++) { menuListPtr->entries[i] = menuListPtr->entries[i + 1]; menuListPtr->entries[i]->index = i; } menuListPtr->numEntries--; if (menuListPtr->numEntries == 0) { ckfree((char *) menuListPtr->entries); menuListPtr->entries = NULL; } } TkMenuConfigureDrawOptions(menuListPtr); /* * Configure the new window to be either a pop-up menu * or a tear-off menu. * We don't do this for menubars since they are not toplevel * windows. Also, since this gets called before CloneMenu has * a chance to set the menuType field, we have to look at the * menuTypeName field to tell that this is a menu bar. */ if (strcmp(menuListPtr->menuTypeName, "normal") == 0) { TkpMakeMenuWindow(menuListPtr->tkwin, 1); } else if (strcmp(menuListPtr->menuTypeName, "tearoff") == 0) { TkpMakeMenuWindow(menuListPtr->tkwin, 0); } /* * After reconfiguring a menu, we need to reconfigure all of the * entries in the menu, since some of the things in the children * (such as graphics contexts) may have to change to reflect changes * in the parent. */ for (i = 0; i < menuListPtr->numEntries; i++) { TkMenuEntry *mePtr; mePtr = menuListPtr->entries[i]; ConfigureMenuEntry(mePtr, 0, (char **) NULL, TK_CONFIG_ARGV_ONLY | COMMAND_MASK << mePtr->type); } TkEventuallyRecomputeMenu(menuListPtr); } return TCL_OK;}/* *---------------------------------------------------------------------- * * ConfigureMenuEntry -- * * This procedure is called to process an argv/argc list in order * to configure (or reconfigure) one entry in a menu. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information such as label and accelerator get * set for mePtr; old resources get freed, if there were any. * *---------------------------------------------------------------------- */static intConfigureMenuEntry(mePtr, argc, argv, flags) register TkMenuEntry *mePtr; /* Information about menu entry; may * or may not already have values for * some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Additional flags to pass to * Tk_ConfigureWidget. */{ TkMenu *menuPtr = mePtr->menuPtr; int index = mePtr->index; Tk_Image image; /* * If this entry is a check button or radio button, then remove * its old trace procedure. */ if ((mePtr->name != NULL) && ((mePtr->type == CHECK_BUTTON_ENTRY) || (mePtr->type == RADIO_BUTTON_ENTRY))) { Tcl_UntraceVar(menuPtr->interp, mePtr->name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, (ClientData) mePtr); } if (menuPtr->tkwin != NULL) { if (Tk_ConfigureWidget(menuPtr->interp, menuPtr->tkwin, tkMenuEntryConfigSpecs, argc, argv, (char *) mePtr, flags | (COMMAND_MASK << mePtr->type)) != TCL_OK) { return TCL_ERROR; } } /* * The code below handles special configuration stuff not taken * care of by Tk_ConfigureWidget, such as special processing for * defaults, sizing strings, graphics contexts, etc. */ if (mePtr->label == NULL) { mePtr->labelLength = 0; } else { mePtr->labelLength = strlen(mePtr->label); } if (mePtr->accel == NULL) { mePtr->accelLength = 0; } else { mePtr->accelLength = strlen(mePtr->accel); } /* * If this is a cascade entry, the platform-specific data of the child * menu has to be updated. Also, the links that point to parents and * cascades have to be updated. */ if ((mePtr->type == CASCADE_ENTRY) && (mePtr->name != NULL)) { TkMenuEntry *cascadeEntryPtr; TkMenu *cascadeMenuPtr; int alreadyThere; TkMenuReferences *menuRefPtr; char *oldHashKey = NULL; /* Initialization only needed to * prevent compiler warning. */ /* * This is a cascade entry. If the menu that the cascade entry * is pointing to has changed, we need to remove this entry * from the list of entries pointing to the old menu, and add a * cascade reference to the list of entries pointing to the * new menu. * * BUG: We are not recloning for special case #3 yet. */ if (mePtr->childMenuRefPtr != NULL) { oldHashKey = Tcl_GetHashKey(TkGetMenuHashTable(menuPtr->interp), mePtr->childMenuRefPtr->hashEntryPtr); if (strcmp(oldHashKey, mePtr->name) != 0) { UnhookCascadeEntry(mePtr); } } if ((mePtr->childMenuRefPtr == NULL) || (strcmp(oldHashKey, mePtr->name) != 0)) { menuRefPtr = TkCreateMenuReferences(menuPtr->interp, mePtr->name); cascadeMenuPtr = menuRefPtr->menuPtr; mePtr->childMenuRefPtr = menuRefPtr; if (menuRefPtr->parentEntryPtr == NULL) { menuRefPtr->parentEntryPtr = mePtr; } else { alreadyThere = 0; for (cascadeEntryPtr = menuRefPtr->parentEntryPtr; cascadeEntryPtr != NULL; cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { if (cascadeEntryPtr == mePtr) { alreadyThere = 1; break; } } /* * Put the item at the front of the list. */ if (!alreadyThere) { mePtr->nextCascadePtr = menuRefPtr->parentEntryPtr; menuRefPtr->parentEntryPtr = mePtr; } } } } if (TkMenuConfigureEntryDrawOptions(mePtr, index) != TCL_OK) { return TCL_ERROR; } if (TkpConfigureMenuEntry(mePtr) != TCL_OK) { return TCL_ERROR; } if ((mePtr->type == CHECK_BUTTON_ENTRY) || (mePtr->type == RADIO_BUTTON_ENTRY)) { char *value; if (mePtr->name == NULL) { mePtr->name = (char *) ckalloc((unsigned) (mePtr->labelLength + 1)); strcpy(mePtr->name, (mePtr->label == NULL) ? "" : mePtr->label); } if (mePtr->onValue == NULL) { mePtr->onValue = (char *) ckalloc((unsigned) (mePtr->labelLength + 1)); strcpy(mePtr->onValue, (mePtr->label == NULL) ? "" : mePtr->label); } /* * Select the entry if the associated variable has the * appropriate value, initialize the variable if it doesn't * exist, then set a trace on the variable to monitor future * changes to its value. */ value = Tcl_GetVar(menuPtr->interp, mePtr->name, TCL_GLOBAL_ONLY); mePtr->entryFlags &= ~ENTRY_SELECTED; if (value != NULL) { if (strcmp(value, mePtr->onValue) == 0) { mePtr->entryFlags |= ENTRY_SELECTED; } } else { Tcl_SetVar(menuPtr->interp, mePtr->name, (mePtr->type == CHECK_BUTTON_ENTRY) ? mePtr->offValue : "", TCL_GLOBAL_ONLY); } Tcl_TraceVar(menuPtr->interp, mePtr->name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, (ClientData) mePtr); } /* * Get the images for the entry, if there are any. Allocate the * new images before freeing the old ones, so that the reference * counts don't go to zero and cause image data to be discarded. */ if (mePtr->imageString != NULL) { image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, mePtr->imageString, TkMenuImageProc, (ClientData) mePtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (mePtr->image != NULL) { Tk_FreeImage(mePtr->image); } mePtr->image = image; if (mePtr->selectImageString != NULL) { image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, mePtr->selectImageString, TkMenuSelectImageProc, (ClientData) mePtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (mePtr->selectImage != NULL) { Tk_FreeImage(mePtr->selectImage); } mePtr->selectImage = image; TkEventuallyRecomputeMenu(menuPtr); return TCL_OK;}/* *---------------------------------------------------------------------- * * ConfigureMenuCloneEntries -- * * Calls ConfigureMenuEntry for each menu in the clone chain. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information such as label and accelerator get * set for mePtr; old resources get freed, if there were any. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -