📄 tkwinmenu.c
字号:
/* * tkWinMenu.c -- * * This module implements the Windows platform-specific features of menus. * * 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. * * SCCS: @(#) tkWinMenu.c 1.102 97/10/28 13:56:58 */#define OEMRESOURCE#include <string.h>#include "tkMenu.h"#include "tkWinInt.h"/* * The class of the window for popup menus. */#define MENU_CLASS_NAME "MenuWindowClass"/* * Used to align a windows bitmap inside a rectangle */#define ALIGN_BITMAP_LEFT 0x00000001#define ALIGN_BITMAP_RIGHT 0x00000002#define ALIGN_BITMAP_TOP 0x00000004#define ALIGN_BITMAP_BOTTOM 0x00000008/* * Platform-specific menu flags: * * MENU_SYSTEM_MENU Non-zero means that the Windows menu handle * was retrieved with GetSystemMenu and needs * to be disposed of specially. * MENU_RECONFIGURE_PENDING * Non-zero means that an idle handler has * been set up to reconfigure the Windows menu * handle for this menu. */#define MENU_SYSTEM_MENU MENU_PLATFORM_FLAG1#define MENU_RECONFIGURE_PENDING MENU_PLATFORM_FLAG2static int indicatorDimensions[2]; /* The dimensions of the indicator space * in a menu entry. Calculated at init * time to save time. */static Tcl_HashTable commandTable; /* A map of command ids to menu entries */static int inPostMenu; /* We cannot be re-entrant like X Windows. */static WORD lastCommandID; /* The last command ID we allocated. */static HWND menuHWND; /* A window to service popup-menu messages * in. */static int oldServiceMode; /* Used while processing a menu; we need * to set the event mode specially when we * enter the menu processing modal loop * and reset it when menus go away. */static TkMenu *modalMenuPtr; /* The menu we are processing inside the modal * loop. We need this to reset all of the * active items when menus go away since * Windows does not see fit to give this * to us when it sends its WM_MENUSELECT. */static OSVERSIONINFO versionInfo; /* So we don't have to keep doing this */static Tcl_HashTable winMenuTable; /* Need this to map HMENUs back to menuPtrs *//* * The following are default menu value strings. */static char borderString[5]; /* The string indicating how big the border is */static Tcl_DString menuFontDString; /* A buffer to store the default menu font * string. *//* * Forward declarations for procedures defined later in this file: */static void DrawMenuEntryAccelerator _ANSI_ARGS_(( TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d, GC gc, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, Tk_3DBorder activeBorder, int x, int y, int width, int height, int drawArrow));static void DrawMenuEntryBackground _ANSI_ARGS_(( TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d, Tk_3DBorder activeBorder, Tk_3DBorder bgBorder, int x, int y, int width, int heigth));static void DrawMenuEntryIndicator _ANSI_ARGS_(( TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d, GC gc, GC indicatorGC, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, int y, int width, int height));static void DrawMenuEntryLabel _ANSI_ARGS_(( TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d, GC gc, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, int y, int width, int height));static void DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d, GC gc, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, int y, int width, int height));static void DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d, GC gc, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, int y, int width, int height));static void DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d, GC gc, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, int y, int width, int height));static void DrawWindowsSystemBitmap _ANSI_ARGS_(( Display *display, Drawable drawable, GC gc, CONST RECT *rectPtr, int bitmapID, int alignFlags));static void FreeID _ANSI_ARGS_((int commandID));static char * GetEntryText _ANSI_ARGS_((TkMenuEntry *mePtr));static void GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, int *heightPtr));static void GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, int *heightPtr));static void GetMenuIndicatorGeometry _ANSI_ARGS_(( TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, int *heightPtr));static void GetMenuSeparatorGeometry _ANSI_ARGS_(( TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, int *heightPtr));static void GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, int *heightPtr));static int GetNewID _ANSI_ARGS_((TkMenuEntry *mePtr, int *menuIDPtr));static void MenuExitProc _ANSI_ARGS_((ClientData clientData));static int MenuKeyBindProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, XEvent *eventPtr, Tk_Window tkwin, KeySym keySym));static void MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr));static void ReconfigureWindowsMenu _ANSI_ARGS_(( ClientData clientData));static void RecursivelyClearActiveMenu _ANSI_ARGS_(( TkMenu *menuPtr));static LRESULT CALLBACK TkWinMenuProc _ANSI_ARGS_((HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam));/* *---------------------------------------------------------------------- * * GetNewID -- * * Allocates a new menu id and marks it in use. * * Results: * Returns TCL_OK if succesful; TCL_ERROR if there are no more * ids of the appropriate type to allocate. menuIDPtr contains * the new id if succesful. * * Side effects: * An entry is created for the menu in the command hash table, * and the hash entry is stored in the appropriate field in the * menu data structure. * *---------------------------------------------------------------------- */static intGetNewID(mePtr, menuIDPtr) TkMenuEntry *mePtr; /* The menu we are working with */ int *menuIDPtr; /* The resulting id */{ int found = 0; int newEntry; Tcl_HashEntry *commandEntryPtr; WORD returnID; WORD curID = lastCommandID + 1; /* * The following code relies on WORD wrapping when the highest value is * incremented. */ while (curID != lastCommandID) { commandEntryPtr = Tcl_CreateHashEntry(&commandTable, (char *) curID, &newEntry); if (newEntry == 1) { found = 1; returnID = curID; break; } curID++; } if (found) { Tcl_SetHashValue(commandEntryPtr, (char *) mePtr); *menuIDPtr = (int) returnID; lastCommandID = returnID; return TCL_OK; } else { return TCL_ERROR; }}/* *---------------------------------------------------------------------- * * FreeID -- * * Marks the itemID as free. * * Results: * None. * * Side effects: * The hash table entry for the ID is cleared. * *---------------------------------------------------------------------- */static voidFreeID(commandID) int commandID;{ Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable, (char *) commandID); if (entryPtr != NULL) { Tcl_DeleteHashEntry(entryPtr); }}/* *---------------------------------------------------------------------- * * TkpNewMenu -- * * Gets a new blank menu. Only the platform specific options are filled * in. * * Results: * Standard TCL error. * * Side effects: * Allocates a Windows menu handle and places it in the platformData * field of the menuPtr. * *---------------------------------------------------------------------- */intTkpNewMenu(menuPtr) TkMenu *menuPtr; /* The common structure we are making the * platform structure for. */{ HMENU winMenuHdl; Tcl_HashEntry *hashEntryPtr; int newEntry; winMenuHdl = CreatePopupMenu(); if (winMenuHdl == NULL) { Tcl_AppendResult(menuPtr->interp, "No more menus can be allocated.", (char *) NULL); return TCL_ERROR; } /* * We hash all of the HMENU's so that we can get their menu ptrs * back when dispatch messages. */ hashEntryPtr = Tcl_CreateHashEntry(&winMenuTable, (char *) winMenuHdl, &newEntry); Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr); menuPtr->platformData = (TkMenuPlatformData) winMenuHdl; return TCL_OK;}/* *---------------------------------------------------------------------- * * TkpDestroyMenu -- * * Destroys platform-specific menu structures. * * Results: * None. * * Side effects: * All platform-specific allocations are freed up. * *---------------------------------------------------------------------- */voidTkpDestroyMenu(menuPtr) TkMenu *menuPtr; /* The common menu structure */{ HMENU winMenuHdl = (HMENU) menuPtr->platformData; if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { Tcl_CancelIdleCall(ReconfigureWindowsMenu, (ClientData) menuPtr); } if (winMenuHdl == NULL) { return; } if (menuPtr->menuFlags & MENU_SYSTEM_MENU) { TkMenuEntry *searchEntryPtr; Tcl_HashTable *tablePtr = TkGetMenuHashTable(menuPtr->interp); char *menuName = Tcl_GetHashKey(tablePtr, menuPtr->menuRefPtr->hashEntryPtr); /* * Search for the menu in the menubar, if it is present, get the * wrapper window associated with the toplevel and reset its * system menu to the default menu. */ for (searchEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; searchEntryPtr != NULL; searchEntryPtr = searchEntryPtr->nextCascadePtr) { if (strcmp(searchEntryPtr->name, menuName) == 0) { Tk_Window parentTopLevelPtr = searchEntryPtr ->menuPtr->parentTopLevelPtr; if (parentTopLevelPtr != NULL) { GetSystemMenu(TkWinGetWrapperWindow(parentTopLevelPtr), TRUE); } break; } } } else { Tcl_HashEntry *hashEntryPtr; /* * Remove the menu from the menu hash table, then destroy the handle. */ hashEntryPtr = Tcl_FindHashEntry(&winMenuTable, (char *) winMenuHdl); if (hashEntryPtr != NULL) { Tcl_DeleteHashEntry(hashEntryPtr); } DestroyMenu(winMenuHdl); } menuPtr->platformData = NULL;}/* *---------------------------------------------------------------------- * * TkpDestroyMenuEntry -- * * Cleans up platform-specific menu entry items. * * Results: * None * * Side effects: * All platform-specific allocations are freed up. * *---------------------------------------------------------------------- */voidTkpDestroyMenuEntry(mePtr) TkMenuEntry *mePtr; /* The entry to destroy */{ TkMenu *menuPtr = mePtr->menuPtr; HMENU winMenuHdl = (HMENU) menuPtr->platformData; if (NULL != winMenuHdl) { if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); } } FreeID((int) mePtr->platformEntryData); mePtr->platformEntryData = NULL;}/* *---------------------------------------------------------------------- * * GetEntryText -- * * Given a menu entry, gives back the text that should go in it. * Separators should be done by the caller, as they have to be * handled specially. Allocates the memory with alloc. The caller * should free the memory. * * Results: * itemText points to the new text for the item. * * Side effects: * None. * *---------------------------------------------------------------------- */static char *GetEntryText(mePtr) TkMenuEntry *mePtr; /* A pointer to the menu entry. */{ char *itemText; if (mePtr->type == TEAROFF_ENTRY) { itemText = ckalloc(sizeof("(Tear-off)")); strcpy(itemText, "(Tear-off)"); } else if (mePtr->imageString != NULL) { itemText = ckalloc(sizeof("(Image)")); strcpy(itemText, "(Image)"); } else if (mePtr->bitmap != None) { itemText = ckalloc(sizeof("(Pixmap)")); strcpy(itemText, "(Pixmap)"); } else if (mePtr->label == NULL || mePtr->labelLength == 0) { itemText = ckalloc(sizeof("( )")); strcpy(itemText, "( )"); } else { int size = mePtr->labelLength + 1; int i, j; /* * We have to construct the string with an ampersand * preceeding the underline character, and a tab seperating * the text and the accel text. We have to be careful with * ampersands in the string. */ for (i = 0; i < mePtr->labelLength; i++) { if (mePtr->label[i] == '&') { size++; } } if (mePtr->underline >= 0) { size++; if (mePtr->label[mePtr->underline] == '&') { size++; } } if (mePtr->accelLength > 0) { size += mePtr->accelLength + 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -