📄 tkmenu.c
字号:
case CHECK_BUTTON_ENTRY: interp->result = "checkbutton"; break; case RADIO_BUTTON_ENTRY: interp->result = "radiobutton"; break; case CASCADE_ENTRY: interp->result = "cascade"; break; case TEAROFF_ENTRY: interp->result = "tearoff"; break; } } else if ((c == 'u') && (strncmp(argv[1], "unpost", length) == 0)) { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " unpost\"", (char *) NULL); goto error; } Tk_UnmapWindow(menuPtr->tkwin); result = TkPostSubmenu(interp, menuPtr, (TkMenuEntry *) NULL); } else if ((c == 'y') && (strncmp(argv[1], "yposition", length) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " yposition index\"", (char *) NULL); goto error; } result = MenuDoYPosition(interp, menuPtr, argv[2]); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be activate, add, cget, clone, configure, delete, ", "entrycget, entryconfigure, index, insert, invoke, ", "post, postcascade, type, unpost, or yposition", (char *) NULL); goto error; } done: Tcl_Release((ClientData) menuPtr); return result; error: Tcl_Release((ClientData) menuPtr); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * TkInvokeMenu -- * * Given a menu and an index, takes the appropriate action for the * entry associated with that index. * * Results: * Standard Tcl result. * * Side effects: * Commands may get excecuted; variables may get set; sub-menus may * get posted. * *---------------------------------------------------------------------- */intTkInvokeMenu(interp, menuPtr, index) Tcl_Interp *interp; /* The interp that the menu lives in. */ TkMenu *menuPtr; /* The menu we are invoking. */ int index; /* The zero based index of the item we * are invoking */{ int result = TCL_OK; TkMenuEntry *mePtr; if (index < 0) { goto done; } mePtr = menuPtr->entries[index]; if (mePtr->state == tkDisabledUid) { goto done; } Tcl_Preserve((ClientData) mePtr); if (mePtr->type == TEAROFF_ENTRY) { Tcl_DString commandDString; Tcl_DStringInit(&commandDString); Tcl_DStringAppendElement(&commandDString, "tkTearOffMenu"); Tcl_DStringAppendElement(&commandDString, Tk_PathName(menuPtr->tkwin)); result = Tcl_Eval(interp, Tcl_DStringValue(&commandDString)); Tcl_DStringFree(&commandDString); } else if (mePtr->type == CHECK_BUTTON_ENTRY) { if (mePtr->entryFlags & ENTRY_SELECTED) { if (Tcl_SetVar(interp, mePtr->name, mePtr->offValue, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } } else { if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } } } else if (mePtr->type == RADIO_BUTTON_ENTRY) { if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } } if ((result == TCL_OK) && (mePtr->command != NULL)) { result = TkCopyAndGlobalEval(interp, mePtr->command); } Tcl_Release((ClientData) mePtr); done: return result; }/* *---------------------------------------------------------------------- * * DestroyMenuInstance -- * * This procedure is invoked by TkDestroyMenu * to clean up the internal structure of a menu at a safe time * (when no-one is using it anymore). Only takes care of one instance * of the menu. * * Results: * None. * * Side effects: * Everything associated with the menu is freed up. * *---------------------------------------------------------------------- */static voidDestroyMenuInstance(menuPtr) TkMenu *menuPtr; /* Info about menu widget. */{ int i, numEntries = menuPtr->numEntries; TkMenu *menuInstancePtr; TkMenuEntry *cascadePtr, *nextCascadePtr; char *newArgv[2]; TkMenu *parentMasterMenuPtr; TkMenuEntry *parentMasterEntryPtr; TkMenu *parentMenuPtr; /* * If the menu has any cascade menu entries pointing to it, the cascade * entries need to be told that the menu is going away. We need to clear * the menu ptr field in the menu reference at this point in the code * so that everything else can forget about this menu properly. We also * need to reset -menu field of all entries that are not master menus * back to this entry name if this is a master menu pointed to by another * master menu. If there is a clone menu that points to this menu, * then this menu is itself a clone, so when this menu goes away, * the -menu field of the pointing entry must be set back to this * menu's master menu name so that later if another menu is created * the cascade hierarchy can be maintained. */ TkpDestroyMenu(menuPtr); cascadePtr = menuPtr->menuRefPtr->parentEntryPtr; menuPtr->menuRefPtr->menuPtr = NULL; TkFreeMenuReferences(menuPtr->menuRefPtr); for (; cascadePtr != NULL; cascadePtr = nextCascadePtr) { parentMenuPtr = cascadePtr->menuPtr; nextCascadePtr = cascadePtr->nextCascadePtr; if (menuPtr->masterMenuPtr != menuPtr) { parentMasterMenuPtr = cascadePtr->menuPtr->masterMenuPtr; parentMasterEntryPtr = parentMasterMenuPtr->entries[cascadePtr->index]; newArgv[0] = "-menu"; newArgv[1] = parentMasterEntryPtr->name; ConfigureMenuEntry(cascadePtr, 2, newArgv, TK_CONFIG_ARGV_ONLY); } else { ConfigureMenuEntry(cascadePtr, 0, (char **) NULL, 0); } } if (menuPtr->masterMenuPtr != menuPtr) { for (menuInstancePtr = menuPtr->masterMenuPtr; menuInstancePtr != NULL; menuInstancePtr = menuInstancePtr->nextInstancePtr) { if (menuInstancePtr->nextInstancePtr == menuPtr) { menuInstancePtr->nextInstancePtr = menuInstancePtr->nextInstancePtr->nextInstancePtr; break; } } } else if (menuPtr->nextInstancePtr != NULL) { panic("Attempting to delete master menu when there are still clones."); } /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ for (i = numEntries - 1; i >= 0; i--) { DestroyMenuEntry((char *) menuPtr->entries[i]); } if (menuPtr->entries != NULL) { ckfree((char *) menuPtr->entries); } TkMenuFreeDrawOptions(menuPtr); Tk_FreeOptions(tkMenuConfigSpecs, (char *) menuPtr, menuPtr->display, 0); Tcl_EventuallyFree((ClientData) menuPtr, TCL_DYNAMIC);}/* *---------------------------------------------------------------------- * * TkDestroyMenu -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a menu at a safe time * (when no-one is using it anymore). If called on a master instance, * destroys all of the slave instances. If called on a non-master * instance, just destroys that instance. * * Results: * None. * * Side effects: * Everything associated with the menu is freed up. * *---------------------------------------------------------------------- */voidTkDestroyMenu(menuPtr) TkMenu *menuPtr; /* Info about menu widget. */{ TkMenu *menuInstancePtr; TkMenuTopLevelList *topLevelListPtr, *nextTopLevelPtr; if (menuPtr->menuFlags & MENU_DELETION_PENDING) { return; } /* * Now destroy all non-tearoff instances of this menu if this is a * parent menu. Is this loop safe enough? Are there going to be * destroy bindings on child menus which kill the parent? If not, * we have to do a slightly more complex scheme. */ if (menuPtr->masterMenuPtr == menuPtr) { menuPtr->menuFlags |= MENU_DELETION_PENDING; while (menuPtr->nextInstancePtr != NULL) { menuInstancePtr = menuPtr->nextInstancePtr; menuPtr->nextInstancePtr = menuInstancePtr->nextInstancePtr; if (menuInstancePtr->tkwin != NULL) { Tk_DestroyWindow(menuInstancePtr->tkwin); } } menuPtr->menuFlags &= ~MENU_DELETION_PENDING; } /* * If any toplevel widgets have this menu as their menubar, * the geometry of the window may have to be recalculated. */ topLevelListPtr = menuPtr->menuRefPtr->topLevelListPtr; while (topLevelListPtr != NULL) { nextTopLevelPtr = topLevelListPtr->nextPtr; TkpSetWindowMenuBar(topLevelListPtr->tkwin, NULL); topLevelListPtr = nextTopLevelPtr; } DestroyMenuInstance(menuPtr);}/* *---------------------------------------------------------------------- * * UnhookCascadeEntry -- * * This entry is removed from the list of entries that point to the * cascade menu. This is done in preparation for changing the menu * that this entry points to. * * Results: * None * * Side effects: * The appropriate lists are modified. * *---------------------------------------------------------------------- */static voidUnhookCascadeEntry(mePtr) TkMenuEntry *mePtr; /* The cascade entry we are removing * from the cascade list. */{ TkMenuEntry *cascadeEntryPtr; TkMenuEntry *prevCascadePtr; TkMenuReferences *menuRefPtr; menuRefPtr = mePtr->childMenuRefPtr; if (menuRefPtr == NULL) { return; } cascadeEntryPtr = menuRefPtr->parentEntryPtr; if (cascadeEntryPtr == NULL) { return; } /* * Singularly linked list deletion. The two special cases are * 1. one element; 2. The first element is the one we want. */ if (cascadeEntryPtr == mePtr) { if (cascadeEntryPtr->nextCascadePtr == NULL) { /* * This is the last menu entry which points to this * menu, so we need to clear out the list pointer in the * cascade itself. */ menuRefPtr->parentEntryPtr = NULL; TkFreeMenuReferences(menuRefPtr); } else { menuRefPtr->parentEntryPtr = cascadeEntryPtr->nextCascadePtr; } mePtr->nextCascadePtr = NULL; } else { for (prevCascadePtr = cascadeEntryPtr, cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr; cascadeEntryPtr != NULL; prevCascadePtr = cascadeEntryPtr, cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { if (cascadeEntryPtr == mePtr){ prevCascadePtr->nextCascadePtr = cascadeEntryPtr->nextCascadePtr; cascadeEntryPtr->nextCascadePtr = NULL; break; } } } mePtr->childMenuRefPtr = NULL;}/* *---------------------------------------------------------------------- * * DestroyMenuEntry -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a menu entry at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the menu entry is freed. * *---------------------------------------------------------------------- */static voidDestroyMenuEntry(memPtr) char *memPtr; /* Pointer to entry to be freed. */{ register TkMenuEntry *mePtr = (TkMenuEntry *) memPtr; TkMenu *menuPtr = mePtr->menuPtr; if (menuPtr->postedCascade == mePtr) { /* * Ignore errors while unposting the menu, since it's possible * that the menu has already been deleted and the unpost will * generate an error. */ TkPostSubmenu(menuPtr->interp, menuPtr, (TkMenuEntry *) NULL); } /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ if (mePtr->type == CASCADE_ENTRY) { UnhookCascadeEntry(mePtr); } if (mePtr->image != NULL) { Tk_FreeImage(mePtr->image); } if (mePtr->selectImage != NULL) { Tk_FreeImage(mePtr->selectImage); } if (mePtr->name != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -