diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2005-08-10 22:02:21 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2005-08-10 22:02:21 (GMT) |
commit | c8d989f48e69bfff4d7cb7214f8f4539e303fd7c (patch) | |
tree | 9d4e60b064aa3377d392ff30035da3ba8ba121ae /win | |
parent | aac661624dd68998883977d90169ef67424e6b7e (diff) | |
download | tk-c8d989f48e69bfff4d7cb7214f8f4539e303fd7c.zip tk-c8d989f48e69bfff4d7cb7214f8f4539e303fd7c.tar.gz tk-c8d989f48e69bfff4d7cb7214f8f4539e303fd7c.tar.bz2 |
Getting more systematic about style
Also start removing _ANSI_ARGS_; the core's required ANSI C for a while now
Also fix [Bug 1252702]; size_t doesn't mix with Tcl_GetStringFromObj
Diffstat (limited to 'win')
-rw-r--r-- | win/tkWinDialog.c | 1652 | ||||
-rw-r--r-- | win/tkWinMenu.c | 1870 |
2 files changed, 1760 insertions, 1762 deletions
diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index f794174..4d56b69 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -5,29 +5,30 @@ * * Copyright (c) 1996-1997 Sun Microsystems, Inc. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinDialog.c,v 1.37 2004/12/20 10:34:21 vincentdarley Exp $ + * RCS: @(#) $Id: tkWinDialog.c,v 1.38 2005/08/10 22:02:22 dkf Exp $ * */ #include "tkWinInt.h" #include "tkFileFilter.h" -#include <commdlg.h> /* includes common dialog functionality */ +#include <commdlg.h> /* includes common dialog functionality */ #ifdef _MSC_VER # pragma comment (lib, "comdlg32.lib") #endif -#include <dlgs.h> /* includes common dialog template defines */ -#include <cderr.h> /* includes the common dialog error codes */ +#include <dlgs.h> /* includes common dialog template defines */ +#include <cderr.h> /* includes the common dialog error codes */ /* * This controls the use of the new style tk_chooseDirectory dialog. */ + #define USE_NEW_CHOOSEDIR 1 #ifdef USE_NEW_CHOOSEDIR -#include <shlobj.h> /* includes SHBrowseForFolder */ +#include <shlobj.h> /* includes SHBrowseForFolder */ #ifdef _MSC_VER # pragma comment (lib, "shell32.lib") #endif @@ -36,47 +37,50 @@ #ifndef BIF_EDITBOX #define BIF_EDITBOX 0x10 #endif + #ifndef BIF_VALIDATE #define BIF_VALIDATE 0x0020 #endif + #ifndef BFFM_VALIDATEFAILED #ifdef UNICODE #define BFFM_VALIDATEFAILED 4 #else #define BFFM_VALIDATEFAILED 3 #endif -#endif +#endif /* BFFM_VALIDATEFAILED */ /* - * The following structure is used by the new Tk_ChooseDirectoryObjCmd - * to pass data between it and its callback. Unqiue to Winodws platform. + * The following structure is used by the new Tk_ChooseDirectoryObjCmd to pass + * data between it and its callback. Unqiue to Winodws platform. */ + typedef struct ChooseDirData { - TCHAR utfInitDir[MAX_PATH]; /* Initial folder to use */ - TCHAR utfRetDir[MAX_PATH]; /* Returned folder to use */ + TCHAR utfInitDir[MAX_PATH]; /* Initial folder to use */ + TCHAR utfRetDir[MAX_PATH]; /* Returned folder to use */ Tcl_Interp *interp; - int mustExist; /* true if file must exist to return from - * callback */ + int mustExist; /* True if file must exist to return from + * callback */ } CHOOSEDIRDATA; #endif -typedef struct ThreadSpecificData { - int debugFlag; /* Flags whether we should output debugging - * information while displaying a builtin - * dialog. */ - Tcl_Interp *debugInterp; /* Interpreter to used for debugging. */ - UINT WM_LBSELCHANGED; /* Holds a registered windows event used for - * communicating between the Directory - * Chooser dialog and its hook proc. */ - HHOOK hMsgBoxHook; /* Hook proc for tk_messageBox and the */ - HICON hSmallIcon; /* icons used by a parent to be used in */ - HICON hBigIcon; /* the message box */ +typedef struct ThreadSpecificData { + int debugFlag; /* Flags whether we should output debugging + * information while displaying a builtin + * dialog. */ + Tcl_Interp *debugInterp; /* Interpreter to used for debugging. */ + UINT WM_LBSELCHANGED; /* Holds a registered windows event used for + * communicating between the Directory Chooser + * dialog and its hook proc. */ + HHOOK hMsgBoxHook; /* Hook proc for tk_messageBox and the */ + HICON hSmallIcon; /* icons used by a parent to be used in */ + HICON hBigIcon; /* the message box */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* - * The following structures are used by Tk_MessageBoxCmd() to parse - * arguments and return results. + * The following structures are used by Tk_MessageBoxCmd() to parse arguments + * and return results. */ static const TkStateMap iconMap[] = { @@ -86,10 +90,10 @@ static const TkStateMap iconMap[] = { {MB_ICONWARNING, "warning"}, {-1, NULL} }; - + static const TkStateMap typeMap[] = { {MB_ABORTRETRYIGNORE, "abortretryignore"}, - {MB_OK, "ok"}, + {MB_OK, "ok"}, {MB_OKCANCEL, "okcancel"}, {MB_RETRYCANCEL, "retrycancel"}, {MB_YESNO, "yesno"}, @@ -114,72 +118,73 @@ static const int buttonFlagMap[] = { static const struct {int type; int btnIds[3];} allowedTypes[] = { {MB_ABORTRETRYIGNORE, {IDABORT, IDRETRY, IDIGNORE}}, - {MB_OK, {IDOK, -1, -1 }}, - {MB_OKCANCEL, {IDOK, IDCANCEL, -1 }}, - {MB_RETRYCANCEL, {IDRETRY, IDCANCEL, -1 }}, - {MB_YESNO, {IDYES, IDNO, -1 }}, - {MB_YESNOCANCEL, {IDYES, IDNO, IDCANCEL}} + {MB_OK, {IDOK, -1, -1 }}, + {MB_OKCANCEL, {IDOK, IDCANCEL, -1 }}, + {MB_RETRYCANCEL, {IDRETRY, IDCANCEL, -1 }}, + {MB_YESNO, {IDYES, IDNO, -1 }}, + {MB_YESNOCANCEL, {IDYES, IDNO, IDCANCEL}} }; #define NUM_TYPES (sizeof(allowedTypes) / sizeof(allowedTypes[0])) /* - * The value of TK_MULTI_MAX_PATH dictactes how many files can - * be retrieved with tk_get*File -multiple 1. It must be allocated - * on the stack, so make it large enough but not too large. -- hobbs - * The data is stored as <dir>\0<file1>\0<file2>\0...<fileN>\0\0. - * MAX_PATH == 260 on Win2K/NT, so *40 is ~10K. + * The value of TK_MULTI_MAX_PATH dictactes how many files can be retrieved + * with tk_get*File -multiple 1. It must be allocated on the stack, so make it + * large enough but not too large. - hobbs + * + * The data is stored as <dir>\0<file1>\0<file2>\0...<fileN>\0\0. Since + * MAX_PATH == 260 on Win2K/NT, *40 is ~10Kbytes. */ #define TK_MULTI_MAX_PATH (MAX_PATH*40) /* * The following structure is used to pass information between the directory - * chooser procedure, Tk_ChooseDirectoryObjCmd(), and its dialog hook proc. + * chooser function, Tk_ChooseDirectoryObjCmd(), and its dialog hook proc. */ typedef struct ChooseDir { - Tcl_Interp *interp; /* Interp, used only if debug is turned on, + Tcl_Interp *interp; /* Interp, used only if debug is turned on, * for setting the "tk_dialog" variable. */ int lastCtrl; /* Used by hook proc to keep track of last - * control that had input focus, so when OK - * is pressed we know whether to browse a - * new directory or return. */ - int lastIdx; /* Last item that was selected in directory + * control that had input focus, so when OK is + * pressed we know whether to browse a new + * directory or return. */ + int lastIdx; /* Last item that was selected in directory * browser listbox. */ - TCHAR path[MAX_PATH]; /* On return from choose directory dialog, - * holds the selected path. Cannot return + TCHAR path[MAX_PATH]; /* On return from choose directory dialog, + * holds the selected path. Cannot return * selected path in ofnPtr->lpstrFile because - * the default dialog proc stores a '\0' in - * it, since, of course, no _file_ was + * the default dialog proc stores a '\0' in + * it, since, of course, no _file_ was * selected. */ OPENFILENAME *ofnPtr; /* pointer to the OFN structure */ } ChooseDir; /* - * Definitions of procedures used only in this file. + * Definitions of functions used only in this file. */ #ifdef USE_NEW_CHOOSEDIR static UINT APIENTRY ChooseDirectoryValidateProc(HWND hdlg, UINT uMsg, LPARAM wParam, LPARAM lParam); #else -static UINT APIENTRY ChooseDirectoryHookProc(HWND hdlg, UINT uMsg, +static UINT APIENTRY ChooseDirectoryHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); #endif static UINT CALLBACK ColorDlgHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -static int GetFileNameA(ClientData clientData, - Tcl_Interp *interp, int objc, +static int GetFileNameA(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int isOpen); -static int GetFileNameW(ClientData clientData, - Tcl_Interp *interp, int objc, +static int GetFileNameW(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int isOpen); -static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr, +static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_DString *dsPtr); -static UINT APIENTRY OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, +static UINT APIENTRY OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -static UINT APIENTRY OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam, +static UINT APIENTRY OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK MsgBoxCBTProc(int nCode, WPARAM wParam, LPARAM lParam); static void SetTkDialog(ClientData clientData); @@ -189,24 +194,23 @@ static void SetTkDialog(ClientData clientData); * * EatSpuriousMessageBugFix -- * - * In the file open/save dialog, double clicking on a list item - * causes the dialog box to close, but an unwanted WM_LBUTTONUP - * message is sent to the window underneath. If the window underneath - * happens to be a windows control (eg a button) then it will be - * activated by accident. - * - * This problem does not occur in dialog boxes, because windows - * must do some special processing to solve the problem. (separate - * message processing functions are used to cope with keyboard - * navigation of controls.) - * - * Here is one solution. After returning, we poll the message queue - * for 1/4s looking for WM_LBUTTON up messages. If we see one it's - * consumed. If we get a WM_LBUTTONDOWN message, then we exit early, - * since the user must be doing something new. This fix only works - * for the current application, so the problem will still occur if - * the open dialog happens to be over another applications button. - * However this is a fairly rare occurrance. + * In the file open/save dialog, double clicking on a list item causes + * the dialog box to close, but an unwanted WM_LBUTTONUP message is sent + * to the window underneath. If the window underneath happens to be a + * windows control (eg a button) then it will be activated by accident. + * + * This problem does not occur in dialog boxes, because windows must do + * some special processing to solve the problem. (separate message + * processing functions are used to cope with keyboard navigation of + * controls.) + * + * Here is one solution. After returning, we poll the message queue for + * 1/4s looking for WM_LBUTTON up messages. If we see one it's consumed. + * If we get a WM_LBUTTONDOWN message, then we exit early, since the user + * must be doing something new. This fix only works for the current + * application, so the problem will still occur if the open dialog + * happens to be over another applications button. However this is a + * fairly rare occurrance. * * Results: * None. @@ -217,15 +221,16 @@ static void SetTkDialog(ClientData clientData); *------------------------------------------------------------------------- */ -static void EatSpuriousMessageBugFix( void ) +static void EatSpuriousMessageBugFix(void) { MSG msg; DWORD nTime = GetTickCount() + 250; - while( GetTickCount() < nTime ) - { - if( PeekMessage(&msg,0,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_NOREMOVE) ) + + while (GetTickCount() < nTime) { + if (PeekMessage(&msg, 0, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE)){ break; - PeekMessage(&msg,0,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE); + } + PeekMessage(&msg, 0, WM_LBUTTONUP, WM_LBUTTONUP, PM_REMOVE); } } @@ -235,8 +240,8 @@ static void EatSpuriousMessageBugFix( void ) * TkWinDialogDebug -- * * Function to turn on/off debugging support for common dialogs under - * windows. The variable "tk_debug" is set to the identifier of the - * dialog window when the modal dialog window pops up and it is safe to + * windows. The variable "tk_debug" is set to the identifier of the + * dialog window when the modal dialog window pops up and it is safe to * send messages to the dialog. * * Results: @@ -248,12 +253,12 @@ static void EatSpuriousMessageBugFix( void ) *------------------------------------------------------------------------- */ -void +void TkWinDialogDebug( int debug) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); tsdPtr->debugFlag = debug; } @@ -263,15 +268,14 @@ TkWinDialogDebug( * * Tk_ChooseColorObjCmd -- * - * This procedure implements the color dialog box for the Windows - * platform. See the user documentation for details on what it - * does. + * This function implements the color dialog box for the Windows + * platform. See the user documentation for details on what it does. * * Results: * See user documentation. * * Side effects: - * A dialog window is created the first time this procedure is called. + * A dialog window is created the first time this function is called. * This window is not destroyed and will be reused the next time the * application invokes the "tk_chooseColor" command. * @@ -302,11 +306,12 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) result = TCL_OK; if (inited == 0) { /* - * dwCustColors stores the custom color which the user can - * modify. We store these colors in a static array so that the next - * time the color dialog pops up, the same set of custom colors - * remain in the dialog. + * dwCustColors stores the custom color which the user can modify. We + * store these colors in a static array so that the next time the + * color dialog pops up, the same set of custom colors remain in the + * dialog. */ + for (i = 0; i < 16; i++) { dwCustColors[i] = RGB(255-i * 10, i, i * 10); } @@ -318,7 +323,7 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) parent = tkwin; chooseColor.lStructSize = sizeof(CHOOSECOLOR); - chooseColor.hwndOwner = NULL; + chooseColor.hwndOwner = NULL; chooseColor.hInstance = NULL; chooseColor.rgbResult = oldColor; chooseColor.lpCustColors = dwCustColors; @@ -340,36 +345,34 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } if (i + 1 == objc) { - string = Tcl_GetStringFromObj(optionPtr, NULL); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", + string = Tcl_GetString(optionPtr); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", (char *) NULL); return TCL_ERROR; } - string = Tcl_GetStringFromObj(valuePtr, NULL); + string = Tcl_GetString(valuePtr); switch ((enum options) index) { - case COLOR_INITIAL: { - XColor *colorPtr; + case COLOR_INITIAL: { + XColor *colorPtr; - colorPtr = Tk_GetColor(interp, tkwin, string); - if (colorPtr == NULL) { - return TCL_ERROR; - } - chooseColor.rgbResult = RGB(colorPtr->red / 0x100, - colorPtr->green / 0x100, colorPtr->blue / 0x100); - break; - } - case COLOR_PARENT: { - parent = Tk_NameToWindow(interp, string, tkwin); - if (parent == NULL) { - return TCL_ERROR; - } - break; + colorPtr = Tk_GetColor(interp, tkwin, string); + if (colorPtr == NULL) { + return TCL_ERROR; } - case COLOR_TITLE: { - chooseColor.lCustData = (LPARAM) string; - break; + chooseColor.rgbResult = RGB(colorPtr->red / 0x100, + colorPtr->green / 0x100, colorPtr->blue / 0x100); + break; + } + case COLOR_PARENT: + parent = Tk_NameToWindow(interp, string, tkwin); + if (parent == NULL) { + return TCL_ERROR; } + break; + case COLOR_TITLE: + chooseColor.lCustData = (LPARAM) string; + break; } } @@ -377,16 +380,17 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) chooseColor.hwndOwner = NULL; hWnd = Tk_GetHWND(Tk_WindowId(parent)); chooseColor.hwndOwner = hWnd; - + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); winCode = ChooseColor(&chooseColor); (void) Tcl_SetServiceMode(oldMode); /* - * Ensure that hWnd is enabled, because it can happen that we - * have updated the wrapper of the parent, which causes us to - * leave this child disabled (Windows loses sync). + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). */ + EnableWindow(hWnd, 1); /* @@ -407,10 +411,10 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) char color[100]; sprintf(color, "#%02x%02x%02x", - GetRValue(chooseColor.rgbResult), - GetGValue(chooseColor.rgbResult), + GetRValue(chooseColor.rgbResult), + GetGValue(chooseColor.rgbResult), GetBValue(chooseColor.rgbResult)); - Tcl_AppendResult(interp, color, NULL); + Tcl_AppendResult(interp, color, NULL); oldColor = chooseColor.rgbResult; result = TCL_OK; } @@ -423,12 +427,12 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) * * ColorDlgHookProc -- * - * Provides special handling of messages for the Color common dialog - * box. Used to set the title when the dialog first appears. + * Provides special handling of messages for the Color common dialog box. + * Used to set the title when the dialog first appears. * * Results: - * The return value is 0 if the default dialog box procedure should - * handle the message, non-zero otherwise. + * The return value is 0 if the default dialog box function should handle + * the message, non-zero otherwise. * * Side effects: * Changes the title of the dialog window. @@ -436,39 +440,38 @@ Tk_ChooseColorObjCmd(clientData, interp, objc, objv) *---------------------------------------------------------------------- */ -static UINT CALLBACK +static UINT CALLBACK ColorDlgHookProc(hDlg, uMsg, wParam, lParam) HWND hDlg; /* Handle to the color dialog. */ UINT uMsg; /* Type of message. */ WPARAM wParam; /* First message parameter. */ LPARAM lParam; /* Second message parameter. */ { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); switch (uMsg) { - case WM_INITDIALOG: { - const char *title; - CHOOSECOLOR *ccPtr; - Tcl_DString ds; + case WM_INITDIALOG: { + const char *title; + CHOOSECOLOR *ccPtr; + Tcl_DString ds; - /* - * Set the title string of the dialog. - */ + /* + * Set the title string of the dialog. + */ - ccPtr = (CHOOSECOLOR *) lParam; - title = (const char *) ccPtr->lCustData; - if ((title != NULL) && (title[0] != '\0')) { - (*tkWinProcs->setWindowText)(hDlg, - Tcl_WinUtfToTChar(title, -1, &ds)); - Tcl_DStringFree(&ds); - } - if (tsdPtr->debugFlag) { - tsdPtr->debugInterp = (Tcl_Interp *) ccPtr->lpTemplateName; - Tcl_DoWhenIdle(SetTkDialog, (ClientData) hDlg); - } - return TRUE; + ccPtr = (CHOOSECOLOR *) lParam; + title = (const char *) ccPtr->lCustData; + if ((title != NULL) && (title[0] != '\0')) { + (*tkWinProcs->setWindowText)(hDlg,Tcl_WinUtfToTChar(title,-1,&ds)); + Tcl_DStringFree(&ds); + } + if (tsdPtr->debugFlag) { + tsdPtr->debugInterp = (Tcl_Interp *) ccPtr->lpTemplateName; + Tcl_DoWhenIdle(SetTkDialog, (ClientData) hDlg); } + return TRUE; + } } return FALSE; } @@ -478,15 +481,14 @@ ColorDlgHookProc(hDlg, uMsg, wParam, lParam) * * Tk_GetOpenFileCmd -- * - * This procedure implements the "open file" dialog box for the - * Windows platform. See the user documentation for details on what - * it does. + * This function implements the "open file" dialog box for the Windows + * platform. See the user documentation for details on what it does. * * Results: * See user documentation. * * Side effects: - * A dialog window is created the first this procedure is called. + * A dialog window is created the first this function is called. * *---------------------------------------------------------------------- */ @@ -552,14 +554,14 @@ Tk_GetSaveFileObjCmd(clientData, interp, objc, objv) *---------------------------------------------------------------------- */ -static int +static int GetFileNameW(clientData, interp, objc, objv, open) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ - int open; /* 1 to call GetOpenFileName(), 0 to - * call GetSaveFileName(). */ + int open; /* 1 to call GetOpenFileName(), 0 to call + * GetSaveFileName(). */ { OPENFILENAMEW ofn; WCHAR file[TK_MULTI_MAX_PATH]; @@ -570,8 +572,8 @@ GetFileNameW(clientData, interp, objc, objv, open) Tcl_DString utfFilterString, utfDirString; Tcl_DString extString, filterString, dirString, titleString; Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding(); - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); static CONST char *saveOptionStrings[] = { "-defaultextension", "-filetypes", "-initialdir", "-initialfile", "-parent", "-title", NULL @@ -619,81 +621,76 @@ GetFileNameW(clientData, interp, objc, objv, open) "option", 0, &index) != TCL_OK) { goto end; } + /* * We want to maximize code sharing between the open and save file * dialog implementations; in particular, the switch statement below. * We use different sets of option strings from the GetIndexFromObj - * call above, but a single enumeration for both. The save file - * dialog doesn't support -multiple, but it falls in the middle of - * the enumeration. Ultimately, this means that when the index found - * by GetIndexFromObj is >= FILE_MULTIPLE, when doing a save file - * dialog, we have to increment the index, so that it matches the - * open file dialog enumeration. + * call above, but a single enumeration for both. The save file dialog + * doesn't support -multiple, but it falls in the middle of the + * enumeration. Ultimately, this means that when the index found by + * GetIndexFromObj is >= FILE_MULTIPLE, when doing a save file dialog, + * we have to increment the index, so that it matches the open file + * dialog enumeration. */ + if (!open && index >= FILE_MULTIPLE) { index++; } if (i + 1 == objc) { - string = Tcl_GetStringFromObj(optionPtr, NULL); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", + string = Tcl_GetString(optionPtr); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", (char *) NULL); goto end; } - string = Tcl_GetStringFromObj(valuePtr, NULL); + string = Tcl_GetString(valuePtr); switch ((enum options) index) { - case FILE_DEFAULT: { - if (string[0] == '.') { - string++; - } - extension = string; - break; + case FILE_DEFAULT: + if (string[0] == '.') { + string++; } - case FILE_TYPES: { - Tcl_DStringFree(&utfFilterString); - if (MakeFilter(interp, valuePtr, &utfFilterString) != TCL_OK) { - goto end; - } - filter = Tcl_DStringValue(&utfFilterString); - break; + extension = string; + break; + case FILE_TYPES: + Tcl_DStringFree(&utfFilterString); + if (MakeFilter(interp, valuePtr, &utfFilterString) != TCL_OK) { + goto end; } - case FILE_INITDIR: { - Tcl_DStringFree(&utfDirString); - if (Tcl_TranslateFileName(interp, string, - &utfDirString) == NULL) { - goto end; - } - break; + filter = Tcl_DStringValue(&utfFilterString); + break; + case FILE_INITDIR: + Tcl_DStringFree(&utfDirString); + if (Tcl_TranslateFileName(interp, string, + &utfDirString) == NULL) { + goto end; } - case FILE_INITFILE: { - Tcl_DString ds; + break; + case FILE_INITFILE: { + Tcl_DString ds; - if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { - goto end; - } - Tcl_UtfToExternal(NULL, unicodeEncoding, Tcl_DStringValue(&ds), - Tcl_DStringLength(&ds), 0, NULL, (char *) file, - sizeof(file), NULL, NULL, NULL); - break; + if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { + goto end; } - case FILE_MULTIPLE: { - if (Tcl_GetBooleanFromObj(interp, valuePtr, - &multi) != TCL_OK) { - return TCL_ERROR; - } - break; - } - case FILE_PARENT: { - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto end; - } - break; + Tcl_UtfToExternal(NULL, unicodeEncoding, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds), 0, NULL, (char *) file, + sizeof(file), NULL, NULL, NULL); + break; + } + case FILE_MULTIPLE: + if (Tcl_GetBooleanFromObj(interp, valuePtr, &multi) != TCL_OK) { + return TCL_ERROR; } - case FILE_TITLE: { - title = string; - break; + break; + case FILE_PARENT: + tkwin = Tk_NameToWindow(interp, string, tkwin); + if (tkwin == NULL) { + goto end; } + break; + case FILE_TITLE: + title = string; + break; } } @@ -707,21 +704,19 @@ GetFileNameW(clientData, interp, objc, objv, open) hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); - ofn.lStructSize = sizeof(OPENFILENAMEW); - ofn.hwndOwner = hWnd; + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = hWnd; #ifdef _WIN64 - ofn.hInstance = (HINSTANCE) GetWindowLongPtr(ofn.hwndOwner, - GWLP_HINSTANCE); + ofn.hInstance = (HINSTANCE) GetWindowLongPtr(ofn.hwndOwner,GWLP_HINSTANCE); #else - ofn.hInstance = (HINSTANCE) GetWindowLong(ofn.hwndOwner, - GWL_HINSTANCE); + ofn.hInstance = (HINSTANCE) GetWindowLong(ofn.hwndOwner, GWL_HINSTANCE); #endif - ofn.lpstrFile = (WCHAR *) file; - ofn.nMaxFile = TK_MULTI_MAX_PATH; - ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST - | OFN_NOCHANGEDIR | OFN_EXPLORER; - ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProcW; - ofn.lCustData = (LPARAM) interp; + ofn.lpstrFile = (WCHAR *) file; + ofn.nMaxFile = TK_MULTI_MAX_PATH; + ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR + | OFN_EXPLORER; + ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProcW; + ofn.lCustData = (LPARAM) interp; if (open != 0) { ofn.Flags |= OFN_FILEMUSTEXIST; @@ -753,10 +748,10 @@ GetFileNameW(clientData, interp, objc, objv, open) Tcl_DStringLength(&utfDirString), &dirString); } else { /* - * NT 5.0 changed the meaning of lpstrInitialDir, so we have - * to ensure that we set the [pwd] if the user didn't specify - * anything else. + * NT 5.0 changed the meaning of lpstrInitialDir, so we have to ensure + * that we set the [pwd] if the user didn't specify anything else. */ + Tcl_DString cwd; Tcl_DStringFree(&utfDirString); @@ -791,10 +786,11 @@ GetFileNameW(clientData, interp, objc, objv, open) EatSpuriousMessageBugFix(); /* - * Ensure that hWnd is enabled, because it can happen that we - * have updated the wrapper of the parent, which causes us to - * leave this child disabled (Windows loses sync). + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). */ + EnableWindow(hWnd, 1); /* @@ -810,12 +806,12 @@ GetFileNameW(clientData, interp, objc, objv, open) if (winCode != 0) { if (ofn.Flags & OFN_ALLOWMULTISELECT) { - /* - * The result in custData->szFile contains many items, - * separated with null characters. It is terminated with - * two nulls in a row. The first element is the directory - * path. + /* + * The result in custData->szFile contains many items, separated + * with null characters. It is terminated with two nulls in a row. + * The first element is the directory path. */ + char *dir; char *p; char *file; @@ -831,13 +827,17 @@ GetFileNameW(clientData, interp, objc, objv, open) files = ofn.lpstrFile; Tcl_ExternalToUtfDString(unicodeEncoding, (char *) files, -1, &ds); - /* Get directory */ + /* + * Get directory. + */ + dir = Tcl_DStringValue(&ds); for (p = dir; p && *p; p++) { /* * Change the pathname to the Tcl "normalized" pathname, where * back slashes are used instead of forward slashes */ + if (*p == '\\') { *p = '/'; } @@ -868,10 +868,12 @@ GetFileNameW(clientData, interp, objc, objv, open) Tcl_DStringFree(&filename); } } + if (count == 0) { /* * Only one file was returned. */ + Tcl_ListObjAppendElement(interp, returnList, Tcl_NewStringObj(dir, -1)); } @@ -881,7 +883,7 @@ GetFileNameW(clientData, interp, objc, objv, open) } else { char *p; Tcl_DString ds; - + Tcl_ExternalToUtfDString(unicodeEncoding, (char *) ofn.lpstrFile, -1, &ds); for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) { @@ -902,25 +904,26 @@ GetFileNameW(clientData, interp, objc, objv, open) * Use the CommDlgExtendedError() function to retrieve the error code. * This function can return one of about two dozen codes; most of * these indicate some sort of gross system failure (insufficient - * memory, bad window handles, etc.). Most of the error codes will be + * memory, bad window handles, etc.). Most of the error codes will be * ignored; as we find we want more specific error messages for * particular errors, we can extend the code as needed. * - * We could also check for FNERR_BUFFERTOOSMALL, but we can't - * really do anything about it when it happens. + * We could also check for FNERR_BUFFERTOOSMALL, but we can't really + * do anything about it when it happens. */ if (CommDlgExtendedError() == FNERR_INVALIDFILENAME) { char *p; Tcl_DString ds; - + Tcl_ExternalToUtfDString(unicodeEncoding, (char *) ofn.lpstrFile, -1, &ds); for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) { /* - * Change the pathname to the Tcl "normalized" pathname, - * where back slashes are used instead of forward slashes + * Change the pathname to the Tcl "normalized" pathname, where + * back slashes are used instead of forward slashes */ + if (*p == '\\') { *p = '/'; } @@ -932,7 +935,7 @@ GetFileNameW(clientData, interp, objc, objv, open) result = TCL_OK; } } - + if (ofn.lpstrTitle != NULL) { Tcl_DStringFree(&titleString); } @@ -944,7 +947,7 @@ GetFileNameW(clientData, interp, objc, objv, open) Tcl_DStringFree(&extString); } - end: + end: Tcl_DStringFree(&utfDirString); Tcl_DStringFree(&utfFilterString); @@ -956,9 +959,8 @@ GetFileNameW(clientData, interp, objc, objv, open) * * OFNHookProcW -- * - * Hook procedure called only if debugging is turned on. Sets - * the "tk_dialog" variable when the dialog is ready to receive - * messages. + * Hook function called only if debugging is turned on. Sets the + * "tk_dialog" variable when the dialog is ready to receive messages. * * Results: * Returns 0 to allow default processing of messages to occur. @@ -969,15 +971,15 @@ GetFileNameW(clientData, interp, objc, objv, open) *------------------------------------------------------------------------- */ -static UINT APIENTRY +static UINT APIENTRY OFNHookProcW( - HWND hdlg, // handle to child dialog window - UINT uMsg, // message identifier - WPARAM wParam, // message parameter - LPARAM lParam) // message parameter + HWND hdlg, /* Handle to child dialog window. */ + UINT uMsg, /* Message identifier */ + WPARAM wParam, /* Message parameter */ + LPARAM lParam) /* Message parameter */ { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); OPENFILENAMEW *ofnPtr; if (uMsg == WM_INITDIALOG) { @@ -988,16 +990,15 @@ OFNHookProcW( #endif } else if (uMsg == WM_WINDOWPOSCHANGED) { /* - * This message is delivered at the right time to enable Tk - * to set the debug information. Unhooks itself so it - * won't set the debug information every time it gets a - * WM_WINDOWPOSCHANGED message. + * This message is delivered at the right time to enable Tk to set the + * debug information. Unhooks itself so it won't set the debug + * information every time it gets a WM_WINDOWPOSCHANGED message. */ #ifdef _WIN64 - ofnPtr = (OPENFILENAMEW *) GetWindowLongPtr(hdlg, GWLP_USERDATA); + ofnPtr = (OPENFILENAMEW *) GetWindowLongPtr(hdlg, GWLP_USERDATA); #else - ofnPtr = (OPENFILENAMEW *) GetWindowLong(hdlg, GWL_USERDATA); + ofnPtr = (OPENFILENAMEW *) GetWindowLong(hdlg, GWL_USERDATA); #endif if (ofnPtr != NULL) { hdlg = GetParent(hdlg); @@ -1029,14 +1030,14 @@ OFNHookProcW( *---------------------------------------------------------------------- */ -static int +static int GetFileNameA(clientData, interp, objc, objv, open) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ - int open; /* 1 to call GetOpenFileName(), 0 to - * call GetSaveFileName(). */ + int open; /* 1 to call GetOpenFileName(), 0 to call + * GetSaveFileName(). */ { OPENFILENAME ofn; TCHAR file[TK_MULTI_MAX_PATH], savePath[MAX_PATH]; @@ -1046,8 +1047,8 @@ GetFileNameA(clientData, interp, objc, objv, open) HWND hWnd; Tcl_DString utfFilterString, utfDirString; Tcl_DString extString, filterString, dirString, titleString; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); static CONST char *saveOptionStrings[] = { "-defaultextension", "-filetypes", "-initialdir", "-initialfile", "-parent", "-title", NULL @@ -1095,81 +1096,75 @@ GetFileNameA(clientData, interp, objc, objv, open) "option", 0, &index) != TCL_OK) { goto end; } + /* * We want to maximize code sharing between the open and save file * dialog implementations; in particular, the switch statement below. * We use different sets of option strings from the GetIndexFromObj - * call above, but a single enumeration for both. The save file - * dialog doesn't support -multiple, but it falls in the middle of - * the enumeration. Ultimately, this means that when the index found - * by GetIndexFromObj is >= FILE_MULTIPLE, when doing a save file - * dialog, we have to increment the index, so that it matches the - * open file dialog enumeration. + * call above, but a single enumeration for both. The save file dialog + * doesn't support -multiple, but it falls in the middle of the + * enumeration. Ultimately, this means that when the index found by + * GetIndexFromObj is >= FILE_MULTIPLE, when doing a save file dialog, + * we have to increment the index, so that it matches the open file + * dialog enumeration. */ + if (!open && index >= FILE_MULTIPLE) { index++; } if (i + 1 == objc) { - string = Tcl_GetStringFromObj(optionPtr, NULL); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", + string = Tcl_GetString(optionPtr); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", (char *) NULL); goto end; } - string = Tcl_GetStringFromObj(valuePtr, NULL); + string = Tcl_GetString(valuePtr); switch ((enum options) index) { - case FILE_DEFAULT: { - if (string[0] == '.') { - string++; - } - extension = string; - break; + case FILE_DEFAULT: + if (string[0] == '.') { + string++; } - case FILE_TYPES: { - Tcl_DStringFree(&utfFilterString); - if (MakeFilter(interp, valuePtr, &utfFilterString) != TCL_OK) { - goto end; - } - filter = Tcl_DStringValue(&utfFilterString); - break; + extension = string; + break; + case FILE_TYPES: + Tcl_DStringFree(&utfFilterString); + if (MakeFilter(interp, valuePtr, &utfFilterString) != TCL_OK) { + goto end; } - case FILE_INITDIR: { - Tcl_DStringFree(&utfDirString); - if (Tcl_TranslateFileName(interp, string, - &utfDirString) == NULL) { - goto end; - } - break; + filter = Tcl_DStringValue(&utfFilterString); + break; + case FILE_INITDIR: + Tcl_DStringFree(&utfDirString); + if (Tcl_TranslateFileName(interp, string, &utfDirString) == NULL) { + goto end; } - case FILE_INITFILE: { - Tcl_DString ds; + break; + case FILE_INITFILE: { + Tcl_DString ds; - if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { - goto end; - } - Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), - Tcl_DStringLength(&ds), 0, NULL, (char *) file, - sizeof(file), NULL, NULL, NULL); - break; + if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { + goto end; } - case FILE_MULTIPLE: { - if (Tcl_GetBooleanFromObj(interp, valuePtr, - &multi) != TCL_OK) { - return TCL_ERROR; - } - break; - } - case FILE_PARENT: { - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto end; - } - break; + Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds), 0, NULL, (char *) file, + sizeof(file), NULL, NULL, NULL); + break; + } + case FILE_MULTIPLE: + if (Tcl_GetBooleanFromObj(interp, valuePtr, &multi) != TCL_OK) { + return TCL_ERROR; } - case FILE_TITLE: { - title = string; - break; + break; + case FILE_PARENT: + tkwin = Tk_NameToWindow(interp, string, tkwin); + if (tkwin == NULL) { + goto end; } + break; + case FILE_TITLE: + title = string; + break; } } @@ -1182,33 +1177,31 @@ GetFileNameA(clientData, interp, objc, objv, open) Tk_MakeWindowExist(tkwin); hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hWnd; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hWnd; #ifdef _WIN64 - ofn.hInstance = (HINSTANCE) GetWindowLongPtr(ofn.hwndOwner, - GWLP_HINSTANCE); + ofn.hInstance = (HINSTANCE) GetWindowLongPtr(ofn.hwndOwner,GWLP_HINSTANCE); #else - ofn.hInstance = (HINSTANCE) GetWindowLong(ofn.hwndOwner, - GWL_HINSTANCE); + ofn.hInstance = (HINSTANCE) GetWindowLong(ofn.hwndOwner, GWL_HINSTANCE); #endif - ofn.lpstrFilter = NULL; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 0; - ofn.lpstrFile = (LPTSTR) file; - ofn.nMaxFile = TK_MULTI_MAX_PATH; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = NULL; - ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST - | OFN_NOCHANGEDIR | OFN_EXPLORER; - ofn.nFileOffset = 0; - ofn.nFileExtension = 0; - ofn.lpstrDefExt = NULL; - ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; - ofn.lCustData = (LPARAM) interp; - ofn.lpTemplateName = NULL; + ofn.lpstrFilter = NULL; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 0; + ofn.lpstrFile = (LPTSTR) file; + ofn.nMaxFile = TK_MULTI_MAX_PATH; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = NULL; + ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR + | OFN_EXPLORER; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = NULL; + ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; + ofn.lCustData = (LPARAM) interp; + ofn.lpTemplateName = NULL; if (open != 0) { ofn.Flags |= OFN_FILEMUSTEXIST; @@ -1237,10 +1230,10 @@ GetFileNameA(clientData, interp, objc, objv, open) Tcl_DStringLength(&utfDirString), &dirString); } else { /* - * NT 5.0 changed the meaning of lpstrInitialDir, so we have - * to ensure that we set the [pwd] if the user didn't specify - * anything else. + * NT 5.0 changed the meaning of lpstrInitialDir, so we have to ensure + * that we set the [pwd] if the user didn't specify anything else. */ + Tcl_DString cwd; Tcl_DStringFree(&utfDirString); @@ -1277,10 +1270,11 @@ GetFileNameA(clientData, interp, objc, objv, open) SetCurrentDirectory(savePath); /* - * Ensure that hWnd is enabled, because it can happen that we - * have updated the wrapper of the parent, which causes us to - * leave this child disabled (Windows loses sync). + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). */ + EnableWindow(hWnd, 1); /* @@ -1296,12 +1290,12 @@ GetFileNameA(clientData, interp, objc, objv, open) if (winCode != 0) { if (ofn.Flags & OFN_ALLOWMULTISELECT) { - /* - * The result in custData->szFile contains many items, - * separated with null characters. It is terminated with - * two nulls in a row. The first element is the directory - * path. + /* + * The result in custData->szFile contains many items, separated + * with null characters. It is terminated with two nulls in a row. + * The first element is the directory path. */ + char *dir; char *p; char *file; @@ -1317,13 +1311,17 @@ GetFileNameA(clientData, interp, objc, objv, open) files = ofn.lpstrFile; Tcl_ExternalToUtfDString(NULL, (char *) files, -1, &ds); - /* Get directory */ + /* + * Get directory. + */ + dir = Tcl_DStringValue(&ds); for (p = dir; p && *p; p++) { /* * Change the pathname to the Tcl "normalized" pathname, where * back slashes are used instead of forward slashes */ + if (*p == '\\') { *p = '/'; } @@ -1358,6 +1356,7 @@ GetFileNameA(clientData, interp, objc, objv, open) /* * Only one file was returned. */ + Tcl_ListObjAppendElement(interp, returnList, Tcl_NewStringObj(dir, -1)); } @@ -1374,6 +1373,7 @@ GetFileNameA(clientData, interp, objc, objv, open) * Change the pathname to the Tcl "normalized" pathname, where * back slashes are used instead of forward slashes */ + if (*p == '\\') { *p = '/'; } @@ -1387,13 +1387,14 @@ GetFileNameA(clientData, interp, objc, objv, open) * Use the CommDlgExtendedError() function to retrieve the error code. * This function can return one of about two dozen codes; most of * these indicate some sort of gross system failure (insufficient - * memory, bad window handles, etc.). Most of the error codes will be - * ignored;; as we find we want specific error messages for particular + * memory, bad window handles, etc.) Most of the error codes will be + * ignored; as we find we want specific error messages for particular * errors, we can extend the code as needed. * - * We could also check for FNERR_BUFFERTOOSMALL, but we can't - * really do anything about it when it happens. + * We could also check for FNERR_BUFFERTOOSMALL, but we can't really + * do anything about it when it happens. */ + if (CommDlgExtendedError() == FNERR_INVALIDFILENAME) { char *p; Tcl_DString ds; @@ -1401,9 +1402,10 @@ GetFileNameA(clientData, interp, objc, objv, open) Tcl_ExternalToUtfDString(NULL, (char *) ofn.lpstrFile, -1, &ds); for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) { /* - * Change the pathname to the Tcl "normalized" pathname, - * where back slashes are used instead of forward slashes + * Change the pathname to the Tcl "normalized" pathname, where + * back slashes are used instead of forward slashes */ + if (*p == '\\') { *p = '/'; } @@ -1427,7 +1429,7 @@ GetFileNameA(clientData, interp, objc, objv, open) Tcl_DStringFree(&extString); } - end: + end: Tcl_DStringFree(&utfDirString); Tcl_DStringFree(&utfFilterString); @@ -1439,9 +1441,8 @@ GetFileNameA(clientData, interp, objc, objv, open) * * OFNHookProc -- * - * Hook procedure called only if debugging is turned on. Sets - * the "tk_dialog" variable when the dialog is ready to receive - * messages. + * Hook function called only if debugging is turned on. Sets the + * "tk_dialog" variable when the dialog is ready to receive messages. * * Results: * Returns 0 to allow default processing of messages to occur. @@ -1452,15 +1453,15 @@ GetFileNameA(clientData, interp, objc, objv, open) *------------------------------------------------------------------------- */ -static UINT APIENTRY +static UINT APIENTRY OFNHookProc( - HWND hdlg, // handle to child dialog window - UINT uMsg, // message identifier - WPARAM wParam, // message parameter - LPARAM lParam) // message parameter + HWND hdlg, /* handle to child dialog window */ + UINT uMsg, /* message identifier */ + WPARAM wParam, /* message parameter */ + LPARAM lParam) /* message parameter */ { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); OPENFILENAME *ofnPtr; if (uMsg == WM_INITDIALOG) { @@ -1471,17 +1472,16 @@ OFNHookProc( #endif } else if (uMsg == WM_WINDOWPOSCHANGED) { /* - * This message is delivered at the right time to both - * old-style and explorer-style hook procs to enable Tk - * to set the debug information. Unhooks itself so it - * won't set the debug information every time it gets a - * WM_WINDOWPOSCHANGED message. + * This message is delivered at the right time to both old-style and + * explorer-style hook procs to enable Tk to set the debug + * information. Unhooks itself so it won't set the debug information + * every time it gets a WM_WINDOWPOSCHANGED message. */ #ifdef _WIN64 - ofnPtr = (OPENFILENAME *) GetWindowLongPtr(hdlg, GWLP_USERDATA); + ofnPtr = (OPENFILENAME *) GetWindowLongPtr(hdlg, GWLP_USERDATA); #else - ofnPtr = (OPENFILENAME *) GetWindowLong(hdlg, GWL_USERDATA); + ofnPtr = (OPENFILENAME *) GetWindowLong(hdlg, GWL_USERDATA); #endif if (ofnPtr != NULL) { if (ofnPtr->Flags & OFN_EXPLORER) { @@ -1505,7 +1505,7 @@ OFNHookProc( * MakeFilter -- * * Allocate a buffer to store the filters in a format understood by - * Windows + * Windows. * * Results: * A standard TCL return value. @@ -1515,8 +1515,9 @@ OFNHookProc( * *---------------------------------------------------------------------- */ -static int -MakeFilter(interp, valuePtr, dsPtr) + +static int +MakeFilter(interp, valuePtr, dsPtr) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Obj *valuePtr; /* Value of the -filetypes option */ Tcl_DString *dsPtr; /* Filled with windows filter string. */ @@ -1553,15 +1554,17 @@ MakeFilter(interp, valuePtr, dsPtr) } else { int len; + if (valuePtr == NULL) { len = 0; } else { CONST char* string = Tcl_GetStringFromObj(valuePtr, &len); } - - /* We format the filetype into a string understood by Windows: - * {"Text Documents" {.doc .txt} {TEXT}} becomes - * "Text Documents (*.doc,*.txt)\0*.doc;*.txt\0" + + /* + * We format the filetype into a string understood by Windows: {"Text + * Documents" {.doc .txt} {TEXT}} becomes "Text Documents + * (*.doc,*.txt)\0*.doc;*.txt\0" * * See the Windows OPENFILENAME manual page for details on the filter * string format. @@ -1571,16 +1574,18 @@ MakeFilter(interp, valuePtr, dsPtr) * Since we may only add asterisks (*) to the filter, we need at most * twice the size of the string to format the filter */ + filterStr = ckalloc((unsigned int) len * 3); for (filterPtr = flist.filters, p = filterStr; filterPtr; - filterPtr = filterPtr->next) { + filterPtr = filterPtr->next) { char *sep; FileFilterClause *clausePtr; /* - * First, put in the name of the file type + * First, put in the name of the file type. */ + strcpy(p, filterPtr->name); p+= strlen(filterPtr->name); *p++ = ' '; @@ -1588,24 +1593,24 @@ MakeFilter(interp, valuePtr, dsPtr) for (pass = 1; pass <= 2; pass++) { /* - * In the first pass, we format the extensions in the - * name field. In the second pass, we format the extensions in - * the filter pattern field + * In the first pass, we format the extensions in the name + * field. In the second pass, we format the extensions in the + * filter pattern field */ + sep = ""; for (clausePtr=filterPtr->clauses;clausePtr; - clausePtr=clausePtr->next) { + clausePtr=clausePtr->next) { GlobPattern *globPtr; - for (globPtr=clausePtr->patterns; globPtr; globPtr=globPtr->next) { strcpy(p, sep); - p+= strlen(sep); + p += strlen(sep); strcpy(p, globPtr->pattern); - p+= strlen(globPtr->pattern); + p += strlen(globPtr->pattern); - if (pass==1) { + if (pass == 1) { sep = ","; } else { sep = ";"; @@ -1613,11 +1618,9 @@ MakeFilter(interp, valuePtr, dsPtr) } } if (pass == 1) { - if (pass == 1) { - *p ++ = ')'; - } + *p ++ = ')'; } - *p ++ = '\0'; + *p++ = '\0'; } } @@ -1625,6 +1628,7 @@ MakeFilter(interp, valuePtr, dsPtr) * Windows requires the filter string to be ended by two NULL * characters. */ + *p++ = '\0'; *p = '\0'; } @@ -1642,77 +1646,78 @@ MakeFilter(interp, valuePtr, dsPtr) * * Tk_ChooseDirectoryObjCmd -- * - * This procedure implements the "tk_chooseDirectory" dialog box - * for the Windows platform. See the user documentation for details - * on what it does. Uses the newer SHBrowseForFolder explorer type - * interface. + * This function implements the "tk_chooseDirectory" dialog box for the + * Windows platform. See the user documentation for details on what it + * does. Uses the newer SHBrowseForFolder explorer type interface. * * Results: - * See user documentation. + * See user documentation. * * Side effects: - * A modal dialog window is created. Tcl_SetServiceMode() is - * called to allow background events to be processed + * A modal dialog window is created. Tcl_SetServiceMode() is called to + * allow background events to be processed * *---------------------------------------------------------------------- - -The procedure tk_chooseDirectory pops up a dialog box for the user to -select a directory. The following option-value pairs are possible as -command line arguments: - --initialdir dirname - -Specifies that the directories in directory should be displayed when the -dialog pops up. If this parameter is not specified, then the directories -in the current working directory are displayed. If the parameter specifies -a relative path, the return value will convert the relative path to an -absolute path. This option may not always work on the Macintosh. This is -not a bug. Rather, the General Controls control panel on the Mac allows -the end user to override the application default directory. - --parent window - -Makes window the logical parent of the dialog. The dialog is displayed on -top of its parent window. - --title titleString - -Specifies a string to display as the title of the dialog box. If this -option is not specified, then a default title will be displayed. - --mustexist boolean - -Specifies whether the user may specify non-existant directories. If this -parameter is true, then the user may only select directories that already -exist. The default value is false. - -New Behaviour: - -- If mustexist = 0 and a user entered folder does not exist, a prompt will - pop-up asking if the user wants another chance to change it. The old - dialog just returned the bogus entry. On mustexist = 1, the entries MUST - exist before exiting the box with OK. - - Bugs: - -- If valid abs directory name is entered into the entry box and Enter - pressed, the box will close returning the name. This is inconsistent when - entering relative names or names with forward slashes, which are - invalidated then corrected in the callback. After correction, the box is - held open to allow further modification by the user. - -- Not sure how to implement localization of message prompts. - -- -title is really -message. -ToDo: -- Fix bugs. -- test to see what platforms this really works on. May require v4.71 - of shell32.dll everywhere (what is standard?). * + * The function tk_chooseDirectory pops up a dialog box for the user to select + * a directory. The following option-value pairs are possible as command line + * arguments: + * + * -initialdir dirname + * + * Specifies that the directories in directory should be displayed when the + * dialog pops up. If this parameter is not specified, then the directories in + * the current working directory are displayed. If the parameter specifies a + * relative path, the return value will convert the relative path to an + * absolute path. This option may not always work on the Macintosh. This is + * not a bug. Rather, the General Controls control panel on the Mac allows the + * end user to override the application default directory. + * + * -parent window + * + * Makes window the logical parent of the dialog. The dialog is displayed on + * top of its parent window. + * + * -title titleString + * + * Specifies a string to display as the title of the dialog box. If this + * option is not specified, then a default title will be displayed. + * + * -mustexist boolean + * + * Specifies whether the user may specify non-existant directories. If this + * parameter is true, then the user may only select directories that already + * exist. The default value is false. + * + * New Behaviour: + * + * - If mustexist = 0 and a user entered folder does not exist, a prompt will + * pop-up asking if the user wants another chance to change it. The old + * dialog just returned the bogus entry. On mustexist = 1, the entries MUST + * exist before exiting the box with OK. + * + * Bugs: + * + * - If valid abs directory name is entered into the entry box and Enter + * pressed, the box will close returning the name. This is inconsistent when + * entering relative names or names with forward slashes, which are + * invalidated then corrected in the callback. After correction, the box is + * held open to allow further modification by the user. + * + * - Not sure how to implement localization of message prompts. + * + * - -title is really -message. + * ToDo: + * - Fix bugs. + * - test to see what platforms this really works on. May require v4.71 of + * shell32.dll everywhere (what is standard?). + * + *---------------------------------------------------------------------- */ + int Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Main window associated with interpreter. */ + ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ @@ -1731,81 +1736,81 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) Tcl_DString titleString; /* UTF Title */ Tcl_DString initDirString; /* Initial directory */ static CONST char *optionStrings[] = { - "-initialdir", "-mustexist", "-parent", "-title", (char *) NULL + "-initialdir", "-mustexist", "-parent", "-title", (char *) NULL }; enum options { - DIR_INITIAL, DIR_EXIST, DIR_PARENT, FILE_TITLE + DIR_INITIAL, DIR_EXIST, DIR_PARENT, FILE_TITLE }; /* * Initialize */ - result = TCL_ERROR; - path[0] = '\0'; - utfTitle = NULL; + + result = TCL_ERROR; + path[0] = '\0'; + utfTitle = NULL; ZeroMemory(&cdCBData, sizeof(CHOOSEDIRDATA)); - cdCBData.interp = interp; + cdCBData.interp = interp; tkwin = (Tk_Window) clientData; + /* * Process the command line options */ + for (i = 1; i < objc; i += 2) { - int index; - char *string; - Tcl_Obj *optionPtr, *valuePtr; - - optionPtr = objv[i]; - valuePtr = objv[i + 1]; - - if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option", - 0, &index) != TCL_OK) { - goto cleanup; - } - if (i + 1 == objc) { - string = Tcl_GetStringFromObj(optionPtr, NULL); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", - (char *) NULL); - goto cleanup; - } + int index; + char *string; + Tcl_Obj *optionPtr, *valuePtr; + + optionPtr = objv[i]; + valuePtr = objv[i + 1]; + + if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option", 0, + &index) != TCL_OK) { + goto cleanup; + } + if (i + 1 == objc) { + string = Tcl_GetString(optionPtr); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", + (char *) NULL); + goto cleanup; + } string = Tcl_GetString(valuePtr); - switch ((enum options) index) { - case DIR_INITIAL: { - if (Tcl_TranslateFileName(interp, string, - &initDirString) == NULL) { - goto cleanup; - } - string = Tcl_DStringValue(&initDirString); - /* - * Convert possible relative path to full path to keep - * dialog happy - */ - GetFullPathName(string, MAX_PATH, saveDir, NULL); - lstrcpyn(cdCBData.utfInitDir, saveDir, MAX_PATH); - Tcl_DStringFree(&initDirString); - break; - } - case DIR_EXIST: { - if (Tcl_GetBooleanFromObj(interp, valuePtr, - &cdCBData.mustExist) != TCL_OK) { - goto cleanup; - } - break; - } - case DIR_PARENT: { - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto cleanup; - } - break; - } - case FILE_TITLE: { - utfTitle = string; - break; - } - } + switch ((enum options) index) { + case DIR_INITIAL: + if (Tcl_TranslateFileName(interp,string,&initDirString) == NULL) { + goto cleanup; + } + string = Tcl_DStringValue(&initDirString); + + /* + * Convert possible relative path to full path to keep dialog + * happy. + */ + + GetFullPathName(string, MAX_PATH, saveDir, NULL); + lstrcpyn(cdCBData.utfInitDir, saveDir, MAX_PATH); + Tcl_DStringFree(&initDirString); + break; + case DIR_EXIST: + if (Tcl_GetBooleanFromObj(interp, valuePtr, + &cdCBData.mustExist) != TCL_OK) { + goto cleanup; + } + break; + case DIR_PARENT: + tkwin = Tk_NameToWindow(interp, string, tkwin); + if (tkwin == NULL) { + goto cleanup; + } + break; + case FILE_TITLE: + utfTitle = string; + break; + } } /* @@ -1819,44 +1824,50 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) * Setup the parameters used by SHBrowseForFolder */ - bInfo.hwndOwner = hWnd; + bInfo.hwndOwner = hWnd; bInfo.pszDisplayName = path; - bInfo.pidlRoot = NULL; + bInfo.pidlRoot = NULL; if (lstrlen(cdCBData.utfInitDir) == 0) { - GetCurrentDirectory(MAX_PATH, cdCBData.utfInitDir); + GetCurrentDirectory(MAX_PATH, cdCBData.utfInitDir); } bInfo.lParam = (LPARAM) &cdCBData; if (utfTitle != NULL) { - Tcl_UtfToExternalDString(NULL, utfTitle, -1, &titleString); - bInfo.lpszTitle = (LPTSTR) Tcl_DStringValue(&titleString); + Tcl_UtfToExternalDString(NULL, utfTitle, -1, &titleString); + bInfo.lpszTitle = (LPTSTR) Tcl_DStringValue(&titleString); } else { - bInfo.lpszTitle = "Please choose a directory, then select OK."; + bInfo.lpszTitle = "Please choose a directory, then select OK."; } /* * Set flags to add edit box (needs 4.71 Shell DLLs), status text line, * validate edit box and */ - bInfo.ulFlags = BIF_EDITBOX | BIF_STATUSTEXT | BIF_RETURNFSANCESTORS - | BIF_VALIDATE; + + bInfo.ulFlags = BIF_EDITBOX | BIF_STATUSTEXT | BIF_RETURNFSANCESTORS + | BIF_VALIDATE; /* * Callback to handle events */ - bInfo.lpfn = (BFFCALLBACK) ChooseDirectoryValidateProc; + + bInfo.lpfn = (BFFCALLBACK) ChooseDirectoryValidateProc; /* - * Display dialog in background and process result. - * We look to give the user a chance to change their mind - * on an invalid folder if mustexist is 0; + * Display dialog in background and process result. We look to give the + * user a chance to change their mind on an invalid folder if mustexist is + * 0; */ oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); GetCurrentDirectory(MAX_PATH, saveDir); if (SHGetMalloc(&pMalloc) == NOERROR) { pidl = SHBrowseForFolder(&bInfo); - /* Null for cancel button or invalid dir, otherwise valid*/ + + /* + * Null for cancel button or invalid dir, otherwise valid. + */ + if (pidl != NULL) { if (!SHGetPathFromIDList(pidl, path)) { Tcl_SetResult(interp, "Error: Not a file system folder\n", @@ -1872,38 +1883,40 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) Tcl_SetServiceMode(oldMode); /* - * Ensure that hWnd is enabled, because it can happen that we - * have updated the wrapper of the parent, which causes us to - * leave this child disabled (Windows loses sync). + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). */ + EnableWindow(hWnd, 1); /* - * Change the pathname to the Tcl "normalized" pathname, where - * back slashes are used instead of forward slashes + * Change the pathname to the Tcl "normalized" pathname, where back + * slashes are used instead of forward slashes */ + Tcl_ResetResult(interp); if (*path) { - char *p; - Tcl_DString ds; + char *p; + Tcl_DString ds; - Tcl_ExternalToUtfDString(NULL, (char *) path, -1, &ds); - for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) { - if (*p == '\\') { - *p = '/'; - } - } - Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL); - Tcl_DStringFree(&ds); + Tcl_ExternalToUtfDString(NULL, (char *) path, -1, &ds); + for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) { + if (*p == '\\') { + *p = '/'; + } + } + Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL); + Tcl_DStringFree(&ds); } result = TCL_OK; if (utfTitle != NULL) { - Tcl_DStringFree(&titleString); + Tcl_DStringFree(&titleString); } - cleanup: + cleanup: return result; } @@ -1912,15 +1925,17 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) * * ChooseDirectoryValidateProc -- * - * Hook procedure called by the explorer ChooseDirectory dialog when events - * occur. It is used to validate the text entry the user may have entered. + * Hook function called by the explorer ChooseDirectory dialog when + * events occur. It is used to validate the text entry the user may have + * entered. * * Results: - * Returns 0 to allow default processing of message, or 1 to - * tell default dialog procedure not to close. + * Returns 0 to allow default processing of message, or 1 to + * tell default dialog function not to close. * *---------------------------------------------------------------------- */ + static UINT APIENTRY ChooseDirectoryValidateProc ( HWND hwnd, @@ -1933,7 +1948,7 @@ ChooseDirectoryValidateProc ( Tcl_DString initDirString; char string[MAX_PATH]; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); chooseDirSharedData = (CHOOSEDIRDATA *)lpData; @@ -1944,120 +1959,123 @@ ChooseDirectoryValidateProc ( #endif if (tsdPtr->debugFlag) { - tsdPtr->debugInterp = (Tcl_Interp *) chooseDirSharedData->interp; - Tcl_DoWhenIdle(SetTkDialog, (ClientData) hwnd); + tsdPtr->debugInterp = (Tcl_Interp *) chooseDirSharedData->interp; + Tcl_DoWhenIdle(SetTkDialog, (ClientData) hwnd); } chooseDirSharedData->utfRetDir[0] = '\0'; switch (message) { - case BFFM_VALIDATEFAILED: - /* - * First save and check to see if it is a valid path name, if - * so then make that path the one shown in the - * window. Otherwise, it failed the check and should be treated - * as such. Use Set/GetCurrentDirectory which allows relative - * path names and names with forward slashes. Use - * Tcl_TranslateFileName to make sure names like ~ are - * converted correctly. - */ - Tcl_TranslateFileName(chooseDirSharedData->interp, - (char *)lParam, &initDirString); - lstrcpyn (string, Tcl_DStringValue(&initDirString), MAX_PATH); - Tcl_DStringFree(&initDirString); - - if (SetCurrentDirectory((char *)string) == 0) { - LPTSTR lpFilePart[MAX_PATH]; - /* - * Get the full path name to the user entry, - * at this point it doesn't exist so see if - * it is supposed to. Otherwise just return it. - */ - GetFullPathName(string, MAX_PATH, - chooseDirSharedData->utfRetDir, /*unused*/ lpFilePart); - if (chooseDirSharedData->mustExist) { - /* - * User HAS to select a valid directory. - */ - wsprintf(selDir, TEXT("Directory '%.200s' does not exist,\nplease select or enter an existing directory."), chooseDirSharedData->utfRetDir); - MessageBox(NULL, selDir, NULL, MB_ICONEXCLAMATION|MB_OK); - return 1; - } - } else { - /* - * Changed to new folder OK, return immediatly with the - * current directory in utfRetDir. - */ - GetCurrentDirectory(MAX_PATH, chooseDirSharedData->utfRetDir); - return 0; - } - return 0; - - case BFFM_SELCHANGED: - /* - * Set the status window to the currently selected path. - * And enable the OK button if a file system folder, otherwise - * disable the OK button for things like server names. - * perhaps a new switch -enablenonfolders can be used to allow - * non folders to be selected. - * - * Not called when user changes edit box directly. - */ - - if (SHGetPathFromIDList((LPITEMIDLIST) lParam, selDir)) { - SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM) selDir); - // enable the OK button - SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); - SetCurrentDirectory(selDir); - } else { - // disable the OK button - SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 0); - } - UpdateWindow(hwnd); - return 1; - - case BFFM_INITIALIZED: { - /* - * Directory browser intializing - tell it where to start from, - * user specified parameter. - */ - char *initDir = chooseDirSharedData->utfInitDir; - - SetCurrentDirectory(initDir); - if (*initDir == '\\') { + case BFFM_VALIDATEFAILED: + /* + * First save and check to see if it is a valid path name, if so then + * make that path the one shown in the window. Otherwise, it failed + * the check and should be treated as such. Use + * Set/GetCurrentDirectory which allows relative path names and names + * with forward slashes. Use Tcl_TranslateFileName to make sure names + * like ~ are converted correctly. + */ + + Tcl_TranslateFileName(chooseDirSharedData->interp, + (char *)lParam, &initDirString); + lstrcpyn (string, Tcl_DStringValue(&initDirString), MAX_PATH); + Tcl_DStringFree(&initDirString); + + if (SetCurrentDirectory((char *)string) == 0) { + LPTSTR lpFilePart[MAX_PATH]; + + /* + * Get the full path name to the user entry, at this point it + * doesn't exist so see if it is supposed to. Otherwise just + * return it. + */ + + GetFullPathName(string, MAX_PATH, + chooseDirSharedData->utfRetDir, /*unused*/ lpFilePart); + if (chooseDirSharedData->mustExist) { /* - * BFFM_SETSELECTION only understands UNC paths as pidls, - * so convert path to pidl using IShellFolder interface. + * User HAS to select a valid directory. */ - LPMALLOC pMalloc; - LPSHELLFOLDER psfFolder; - - if (SUCCEEDED(SHGetMalloc(&pMalloc))) { - if (SUCCEEDED(SHGetDesktopFolder(&psfFolder))) { - LPITEMIDLIST pidlMain; - ULONG ulCount, ulAttr; - Tcl_DString ds; - - Tcl_UtfToExternalDString(TkWinGetUnicodeEncoding(), - initDir, -1, &ds); - if (SUCCEEDED(psfFolder->lpVtbl->ParseDisplayName( - psfFolder, hwnd, NULL, - (WCHAR *) Tcl_DStringValue(&ds), - &ulCount, &pidlMain, &ulAttr)) - && (pidlMain != NULL)) { - SendMessage(hwnd, BFFM_SETSELECTION, FALSE, - (LPARAM)pidlMain); - pMalloc->lpVtbl->Free(pMalloc, pidlMain); - } - psfFolder->lpVtbl->Release(psfFolder); - Tcl_DStringFree(&ds); + + wsprintf(selDir, TEXT("Directory '%.200s' does not exist,\nplease select or enter an existing directory."), chooseDirSharedData->utfRetDir); + MessageBox(NULL, selDir, NULL, MB_ICONEXCLAMATION|MB_OK); + return 1; + } + } else { + /* + * Changed to new folder OK, return immediatly with the + * current directory in utfRetDir. + */ + GetCurrentDirectory(MAX_PATH, chooseDirSharedData->utfRetDir); + return 0; + } + return 0; + + case BFFM_SELCHANGED: + /* + * Set the status window to the currently selected path. And enable + * the OK button if a file system folder, otherwise disable the OK + * button for things like server names. Perhaps a new switch + * -enablenonfolders can be used to allow non folders to be selected. + * + * Not called when user changes edit box directly. + */ + + if (SHGetPathFromIDList((LPITEMIDLIST) lParam, selDir)) { + SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM) selDir); + // enable the OK button + SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); + SetCurrentDirectory(selDir); + } else { + // disable the OK button + SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 0); + } + UpdateWindow(hwnd); + return 1; + + case BFFM_INITIALIZED: { + /* + * Directory browser intializing - tell it where to start from, user + * specified parameter. + */ + + char *initDir = chooseDirSharedData->utfInitDir; + + SetCurrentDirectory(initDir); + if (*initDir == '\\') { + /* + * BFFM_SETSELECTION only understands UNC paths as pidls, + * so convert path to pidl using IShellFolder interface. + */ + + LPMALLOC pMalloc; + LPSHELLFOLDER psfFolder; + + if (SUCCEEDED(SHGetMalloc(&pMalloc))) { + if (SUCCEEDED(SHGetDesktopFolder(&psfFolder))) { + LPITEMIDLIST pidlMain; + ULONG ulCount, ulAttr; + Tcl_DString ds; + + Tcl_UtfToExternalDString(TkWinGetUnicodeEncoding(), + initDir, -1, &ds); + if (SUCCEEDED(psfFolder->lpVtbl->ParseDisplayName( + psfFolder, hwnd, NULL, (WCHAR *) + Tcl_DStringValue(&ds), &ulCount,&pidlMain,&ulAttr)) + && (pidlMain != NULL)) { + SendMessage(hwnd, BFFM_SETSELECTION, FALSE, + (LPARAM)pidlMain); + pMalloc->lpVtbl->Free(pMalloc, pidlMain); } - pMalloc->lpVtbl->Release(pMalloc); + psfFolder->lpVtbl->Release(psfFolder); + Tcl_DStringFree(&ds); } - } else { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)initDir); + pMalloc->lpVtbl->Release(pMalloc); } - SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); - break; + } else { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)initDir); } + SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); + break; + } } return 0; @@ -2068,16 +2086,16 @@ ChooseDirectoryValidateProc ( * * Tk_ChooseDirectoryObjCmd -- * - * This procedure implements the "tk_chooseDirectory" dialog box - * for the Windows platform. See the user documentation for details - * on what it does. + * This function implements the "tk_chooseDirectory" dialog box for the + * Windows platform. See the user documentation for details on what it + * does. * * Results: * See user documentation. * * Side effects: - * A modal dialog window is created. Tcl_SetServiceMode() is - * called to allow background events to be processed + * A modal dialog window is created. Tcl_SetServiceMode() is called to + * allow background events to be processed * *---------------------------------------------------------------------- */ @@ -2098,8 +2116,8 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) char *utfTitle; Tcl_DString utfDirString; Tcl_DString titleString, dirString; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); static CONST char *optionStrings[] = { "-initialdir", "-mustexist", "-parent", "-title", NULL @@ -2109,9 +2127,9 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) }; if (tsdPtr->WM_LBSELCHANGED == 0) { - tsdPtr->WM_LBSELCHANGED = RegisterWindowMessage(LBSELCHSTRING); + tsdPtr->WM_LBSELCHANGED = RegisterWindowMessage(LBSELCHSTRING); } - + result = TCL_ERROR; path[0] = '\0'; @@ -2128,44 +2146,39 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) optionPtr = objv[i]; valuePtr = objv[i + 1]; - if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option", - 0, &index) != TCL_OK) { + if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option", 0, + &index) != TCL_OK) { goto cleanup; } if (i + 1 == objc) { - string = Tcl_GetStringFromObj(optionPtr, NULL); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", + string = Tcl_GetString(optionPtr); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", (char *) NULL); goto cleanup; } - string = Tcl_GetStringFromObj(valuePtr, NULL); + string = Tcl_GetString(valuePtr); switch ((enum options) index) { - case DIR_INITIAL: { - Tcl_DStringFree(&utfDirString); - if (Tcl_TranslateFileName(interp, string, - &utfDirString) == NULL) { - goto cleanup; - } - break; - } - case DIR_EXIST: { - if (Tcl_GetBooleanFromObj(interp, valuePtr, &mustExist) != TCL_OK) { - goto cleanup; - } - break; + case DIR_INITIAL: + Tcl_DStringFree(&utfDirString); + if (Tcl_TranslateFileName(interp, string, &utfDirString) == NULL) { + goto cleanup; } - case DIR_PARENT: { - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto cleanup; - } - break; + break; + case DIR_EXIST: + if (Tcl_GetBooleanFromObj(interp,valuePtr,&mustExist) != TCL_OK) { + goto cleanup; } - case FILE_TITLE: { - utfTitle = string; - break; + break; + case DIR_PARENT: + tkwin = Tk_NameToWindow(interp, string, tkwin); + if (tkwin == NULL) { + goto cleanup; } + break; + case FILE_TITLE: + utfTitle = string; + break; } } @@ -2175,43 +2188,40 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) cd.interp = interp; cd.ofnPtr = &ofn; - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hWnd; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hWnd; #ifdef _WIN64 - ofn.hInstance = (HINSTANCE) GetWindowLongPtr(ofn.hwndOwner, - GWLP_HINSTANCE); + ofn.hInstance = (HINSTANCE) GetWindowLongPtr(ofn.hwndOwner,GWLP_HINSTANCE); #else - ofn.hInstance = (HINSTANCE) GetWindowLong(ofn.hwndOwner, - GWL_HINSTANCE); + ofn.hInstance = (HINSTANCE) GetWindowLong(ofn.hwndOwner, GWL_HINSTANCE); #endif - ofn.lpstrFilter = NULL; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 0; - ofn.lpstrFile = NULL; //(TCHAR *) path; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = NULL; - ofn.Flags = OFN_HIDEREADONLY - | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE; - ofn.nFileOffset = 0; - ofn.nFileExtension = 0; - ofn.lpstrDefExt = NULL; - ofn.lCustData = (LPARAM) &cd; - ofn.lpfnHook = (LPOFNHOOKPROC) ChooseDirectoryHookProc; - ofn.lpTemplateName = MAKEINTRESOURCE(FILEOPENORD); + ofn.lpstrFilter = NULL; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 0; + ofn.lpstrFile = NULL; //(TCHAR *) path; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = NULL; + ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = NULL; + ofn.lCustData = (LPARAM) &cd; + ofn.lpfnHook = (LPOFNHOOKPROC) ChooseDirectoryHookProc; + ofn.lpTemplateName = MAKEINTRESOURCE(FILEOPENORD); if (Tcl_DStringValue(&utfDirString)[0] != '\0') { - Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString), + Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString), Tcl_DStringLength(&utfDirString), &dirString); } else { /* - * NT 5.0 changed the meaning of lpstrInitialDir, so we have - * to ensure that we set the [pwd] if the user didn't specify - * anything else. + * NT 5.0 changed the meaning of lpstrInitialDir, so we have to ensure + * that we set the [pwd] if the user didn't specify anything else. */ + Tcl_DString cwd; Tcl_DStringFree(&utfDirString); @@ -2236,10 +2246,10 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) } /* - * Display dialog. The choose directory dialog doesn't preserve the + * Display dialog. The choose directory dialog doesn't preserve the * current directory, so it must be saved and restored here. */ - + GetCurrentDirectory(MAX_PATH, savePath); mode = Tcl_SetServiceMode(TCL_SERVICE_ALL); code = GetOpenFileName(&ofn); @@ -2247,17 +2257,18 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) SetCurrentDirectory(savePath); /* - * Ensure that hWnd is enabled, because it can happen that we - * have updated the wrapper of the parent, which causes us to - * leave this child disabled (Windows loses sync). + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). */ + EnableWindow(hWnd, 1); Tcl_ResetResult(interp); if (code != 0) { /* - * Change the pathname to the Tcl "normalized" pathname, where - * back slashes are used instead of forward slashes + * Change the pathname to the Tcl "normalized" pathname, where back + * slashes are used instead of forward slashes */ char *p; @@ -2281,7 +2292,7 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) } result = TCL_OK; - cleanup: + cleanup: Tcl_DStringFree(&utfDirString); return result; @@ -2292,35 +2303,33 @@ Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv) * * ChooseDirectoryHookProc -- * - * Hook procedure called by the ChooseDirectory dialog to modify - * its default behavior. The ChooseDirectory dialog is really an - * OpenFile dialog with certain controls rearranged and certain - * behaviors changed. For instance, typing a name in the - * ChooseDirectory dialog selects a directory, rather than - * selecting a file. + * Hook function called by the ChooseDirectory dialog to modify its + * default behavior. The ChooseDirectory dialog is really an OpenFile + * dialog with certain controls rearranged and certain behaviors changed. + * For instance, typing a name in the ChooseDirectory dialog selects a + * directory, rather than selecting a file. * * Results: - * Returns 0 to allow default processing of message, or 1 to - * tell default dialog procedure not to process the message. + * Returns 0 to allow default processing of message, or 1 to tell default + * dialog function not to process the message. * * Side effects: - * A dialog window is created the first this procedure is called. - * This window is not destroyed and will be reused the next time - * the application invokes the "tk_getOpenFile" or - * "tk_getSaveFile" command. + * A dialog window is created the first this function is called. This + * window is not destroyed and will be reused the next time the + * application invokes the "tk_getOpenFile" or "tk_getSaveFile" command. * *---------------------------------------------------------------------- */ -static UINT APIENTRY +static UINT APIENTRY ChooseDirectoryHookProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); OPENFILENAME *ofnPtr; ChooseDir *cdPtr; @@ -2353,7 +2362,7 @@ ChooseDirectoryHookProc( /* * GWL_USERDATA keeps track of cdPtr. */ - + #ifdef _WIN64 cdPtr = (ChooseDir *) GetWindowLongPtr(hwnd, GWLP_USERDATA); #else @@ -2366,15 +2375,15 @@ ChooseDirectoryHookProc( if (message == tsdPtr->WM_LBSELCHANGED) { /* - * Called when double-clicking on directory. - * If directory wasn't already open, browse that directory. - * If directory was already open, return selected directory. + * Called when double-clicking on directory. If directory wasn't + * already open, browse that directory. If directory was already open, + * return selected directory. */ int idCtrl, thisItem; idCtrl = (int) wParam; - thisItem = LOWORD(lParam); + thisItem = LOWORD(lParam); GetCurrentDirectory(MAX_PATH, cdPtr->path); if (idCtrl == lst2) { @@ -2404,18 +2413,17 @@ ChooseDirectoryHookProc( } /* - * Dialogs also get the message that OK was clicked when Enter - * is pressed in some other control. Find out what window - * we were really in when we got the supposed "OK", because the - * behavior is different. + * Dialogs also get the message that OK was clicked when Enter is + * pressed in some other control. Find out what window we were really + * in when we got the supposed "OK", because the behavior is + * different. */ if (cdPtr->lastCtrl == edt10) { /* - * Hit Enter or clicked OK while typing a directory name in the - * edit control. - * If it's a new name, try to go to that directory. - * If the name hasn't changed since last time, return selected + * Hit Enter or clicked OK while typing a directory name in the + * edit control. If it's a new name, try to go to that directory. + * If the name hasn't changed since last time, return selected * directory. */ @@ -2436,7 +2444,7 @@ ChooseDirectoryHookProc( if (ofnPtr->Flags & OFN_PATHMUSTEXIST) { /* - * Directory must exist. Complain, then rehighlight text. + * Directory must exist. Complain, then rehighlight text. */ wsprintf(tmp, _T("Cannot change directory to \"%.200s\"."), @@ -2444,46 +2452,45 @@ ChooseDirectoryHookProc( MessageBox(hwnd, tmp, NULL, MB_OK); SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1); return 0; - } + } if (changed) { /* * Directory was invalid, but we want to keep displaying - * this name. Don't update the listbox that displays the + * this name. Don't update the listbox that displays the * current directory heirarchy, or it'll erase the name. */ - + SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1); return 0; } } if (changed == 0) { /* - * Name hasn't changed since the last time we hit return - * or double-clicked on a directory, so return this. + * Name hasn't changed since the last time we hit return or + * double-clicked on a directory, so return this. */ EndDialog(hwnd, IDOK); return 1; } - + cdPtr->lastCtrl = IDOK; /* - * The following is the magic code, determined by running - * Spy++ on some other directory chooser, that it takes to - * get this dialog to update the listbox to display the - * current directory. + * The following is the magic code, determined by running Spy++ on + * some other directory chooser, that it takes to get this dialog + * to update the listbox to display the current directory. */ SetDlgItemText(hwnd, edt1, cdPtr->path); - SendMessage(hwnd, WM_COMMAND, (WPARAM) MAKELONG(cmb2, 0x8003), + SendMessage(hwnd, WM_COMMAND, (WPARAM) MAKELONG(cmb2, 0x8003), (LPARAM) GetDlgItem(hwnd, cmb2)); return 0; } else if (idCtrl == lst2) { /* - * Enter key was pressed while in listbox. - * If it's a new directory, allow default behavior to open dir. - * If the directory hasn't changed, return selected directory. + * Enter key was pressed while in listbox. If it's a new + * directory, allow default behavior to open dir. If the directory + * hasn't changed, return selected directory. */ int thisItem; @@ -2495,9 +2502,9 @@ ChooseDirectoryHookProc( return 1; } } else if (idCtrl == IDOK) { - /* + /* * The OK button was clicked. Return the value currently selected - * in the entry. + * in the entry. */ GetCurrentDirectory(MAX_PATH, cdPtr->path); @@ -2514,15 +2521,14 @@ ChooseDirectoryHookProc( * * Tk_MessageBoxObjCmd -- * - * This procedure implements the MessageBox window for the - * Windows platform. See the user documentation for details on what - * it does. + * This function implements the MessageBox window for the Windows + * platform. See the user documentation for details on what it does. * * Results: * See user documentation. * * Side effects: - * None. The MessageBox window will be destroy before this procedure + * None. The MessageBox window will be destroy before this function * returns. * *---------------------------------------------------------------------- @@ -2551,18 +2557,18 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) MSG_DEFAULT, MSG_DETAIL, MSG_ICON, MSG_MESSAGE, MSG_PARENT, MSG_TITLE, MSG_TYPE }; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); tkwin = (Tk_Window) clientData; - defaultBtn = -1; - detail = NULL; - icon = MB_ICONINFORMATION; - message = NULL; - parent = tkwin; - title = NULL; - type = MB_OK; + defaultBtn = -1; + detail = NULL; + icon = MB_ICONINFORMATION; + message = NULL; + parent = tkwin; + title = NULL; + type = MB_OK; for (i = 1; i < objc; i += 2) { int index; @@ -2577,16 +2583,16 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } if (i + 1 == objc) { - string = Tcl_GetStringFromObj(optionPtr, NULL); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", + string = Tcl_GetString(optionPtr); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", (char *) NULL); return TCL_ERROR; } - string = Tcl_GetStringFromObj(valuePtr, NULL); + string = Tcl_GetString(valuePtr); switch ((enum options) index) { - case MSG_DEFAULT: - defaultBtn = TkFindStateNumObj(interp, optionPtr, buttonMap, + case MSG_DEFAULT: + defaultBtn = TkFindStateNumObj(interp, optionPtr, buttonMap, valuePtr); if (defaultBtn < 0) { return TCL_ERROR; @@ -2608,7 +2614,7 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) message = string; break; - case MSG_PARENT: + case MSG_PARENT: parent = Tk_NameToWindow(interp, string, tkwin); if (parent == NULL) { return TCL_ERROR; @@ -2625,13 +2631,12 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } break; - } } Tk_MakeWindowExist(parent); hWnd = Tk_GetHWND(Tk_WindowId(parent)); - + flags = 0; if (defaultBtn >= 0) { int defaultBtnIdx; @@ -2649,7 +2654,7 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) } if (defaultBtnIdx < 0) { Tcl_AppendResult(interp, "invalid default button \"", - TkFindStateString(buttonMap, defaultBtn), + TkFindStateString(buttonMap, defaultBtn), "\"", NULL); return TCL_ERROR; } @@ -2683,13 +2688,14 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); /* - * MessageBoxW exists for all platforms. Use it to allow unicode - * error message to be displayed correctly where possible by the OS. + * MessageBoxW exists for all platforms. Use it to allow unicode error + * message to be displayed correctly where possible by the OS. * - * In order to have the parent window icon reflected in a MessageBox, - * we have to create a hook that will trigger when the MessageBox is - * being created. + * In order to have the parent window icon reflected in a MessageBox, we + * have to create a hook that will trigger when the MessageBox is being + * created. */ + tsdPtr->hSmallIcon = TkWinGetIcon(parent, ICON_SMALL); tsdPtr->hBigIcon = TkWinGetIcon(parent, ICON_BIG); tsdPtr->hMsgBoxHook = SetWindowsHookEx(WH_CBT, MsgBoxCBTProc, NULL, @@ -2700,10 +2706,11 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) (void) Tcl_SetServiceMode(oldMode); /* - * Ensure that hWnd is enabled, because it can happen that we - * have updated the wrapper of the parent, which causes us to - * leave this child disabled (Windows loses sync). + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). */ + EnableWindow(hWnd, 1); Tcl_DStringFree(&messageString); @@ -2716,41 +2723,50 @@ Tk_MessageBoxObjCmd(clientData, interp, objc, objv) static LRESULT CALLBACK MsgBoxCBTProc(int nCode, WPARAM wParam, LPARAM lParam) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (nCode == HCBT_CREATEWND) { /* - * Window owned by our task is being created. Since the hook is + * Window owned by our task is being created. Since the hook is * installed just before the MessageBox call and removed after the - * MessageBox call, the window being created is either the message - * box or one of its controls. Check that the class is WC_DIALOG - * to ensure that it's the one we want. + * MessageBox call, the window being created is either the message box + * or one of its controls. Check that the class is WC_DIALOG to ensure + * that it's the one we want. */ + LPCBT_CREATEWND lpcbtcreate = (LPCBT_CREATEWND)lParam; if (WC_DIALOG == lpcbtcreate->lpcs->lpszClass) { HWND hwnd = (HWND) wParam; SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) tsdPtr->hSmallIcon); - SendMessage(hwnd, WM_SETICON, ICON_BIG, - (LPARAM) tsdPtr->hBigIcon); + SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) tsdPtr->hBigIcon); } } /* * Call the next hook proc, if there is one */ + return CallNextHookEx(tsdPtr->hMsgBoxHook, nCode, wParam, lParam); } -static void +static void SetTkDialog(ClientData clientData) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); char buf[32]; sprintf(buf, "0x%p", (HWND) clientData); Tcl_SetVar(tsdPtr->debugInterp, "tk_dialog", buf, TCL_GLOBAL_ONLY); } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index a33ddb8..0234f5a 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -1,15 +1,16 @@ -/* +/* * tkWinMenu.c -- * - * This module implements the Windows platform-specific features of menus. + * This module implements the Windows platform-specific features of + * menus. * * Copyright (c) 1996-1998 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinMenu.c,v 1.44 2005/04/28 02:40:19 chengyemao Exp $ + * RCS: @(#) $Id: tkWinMenu.c,v 1.45 2005/08/10 22:02:22 dkf Exp $ */ #define OEMRESOURCE @@ -22,55 +23,55 @@ * The class of the window for popup menus. */ -#define MENU_CLASS_NAME "MenuWindowClass" -#define EMBEDDED_MENU_CLASS_NAME "EmbeddedMenuWindowClass" +#define MENU_CLASS_NAME "MenuWindowClass" +#define EMBEDDED_MENU_CLASS_NAME "EmbeddedMenuWindowClass" /* * 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 +#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_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. + * 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_FLAG2 +#define MENU_SYSTEM_MENU MENU_PLATFORM_FLAG1 +#define MENU_RECONFIGURE_PENDING MENU_PLATFORM_FLAG2 static int indicatorDimensions[2]; - /* The dimensions of the indicator space - * in a menu entry. Calculated at init - * time to save time. */ + /* The dimensions of the indicator space in a + * menu entry. Calculated at init time to save + * time. */ typedef struct ThreadSpecificData { Tcl_HashTable commandTable; /* A map of command ids to menu entries */ int inPostMenu; /* We cannot be re-entrant like X Windows. */ - WORD lastCommandID; /* The last command ID we allocated. */ + WORD lastCommandID; /* The last command ID we allocated. */ HWND menuHWND; /* A window to service popup-menu messages * in. */ - HWND embeddedMenuHWND; /* A window to service embedded menu messages */ - 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. */ + HWND embeddedMenuHWND; /* A window to service embedded menu + * messages */ + 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. */ TkMenu *modalMenuPtr; /* The menu we are processing inside the modal - * loop. We need this to reset all of the + * 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. */ + * Windows does not see fit to give this to us + * when it sends its WM_MENUSELECT. */ Tcl_HashTable winMenuTable; /* Need this to map HMENUs back to menuPtrs */ } ThreadSpecificData; @@ -85,91 +86,78 @@ static Tcl_DString menuFontDString; /* A buffer to store the default menu font * string. */ /* - * Forward declarations for procedures defined later in this file: + * Forward declarations for functions 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)); -static void DrawMenuEntryArrow _ANSI_ARGS_(( - TkMenu *menuPtr, TkMenuEntry *mePtr, - Drawable d, GC gc, +static void DrawMenuEntryAccelerator(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, + int width, int height); +static void DrawMenuEntryArrow(TkMenu *menuPtr, TkMenuEntry *mePtr, + Drawable d, GC gc, Tk_3DBorder activeBorder, + int x,int y, int width, int height, int drawArrow); +static void DrawMenuEntryBackground(TkMenu *menuPtr, + TkMenuEntry *mePtr, Drawable d, + Tk_3DBorder activeBorder, Tk_3DBorder bgBorder, + int x, int y, int width, int heigth); +static void DrawMenuEntryIndicator(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, + int width, int height); +static void DrawMenuEntryLabel(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, + int width, int height); +static void DrawMenuSeparator(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(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(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_((WORD commandID)); -static TCHAR * GetEntryText _ANSI_ARGS_((TkMenuEntry *mePtr)); -static void GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr, + int y, int width, int height); +static void DrawWindowsSystemBitmap(Display *display, + Drawable drawable, GC gc, CONST RECT *rectPtr, + int bitmapID, int alignFlags); +static void FreeID(WORD commandID); +static TCHAR * GetEntryText(TkMenuEntry *mePtr); +static void GetMenuAccelGeometry(TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, - int *heightPtr)); -static void GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr, + int *heightPtr); +static void GetMenuLabelGeometry(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, + int *widthPtr, int *heightPtr); +static void GetMenuIndicatorGeometry(TkMenu *menuPtr, + TkMenuEntry *mePtr, Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, + int *widthPtr, int *heightPtr); +static void GetMenuSeparatorGeometry(TkMenu *menuPtr, + TkMenuEntry *mePtr, Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, + int *widthPtr, int *heightPtr); +static void GetTearoffEntryGeometry(TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *widthPtr, - int *heightPtr)); -static int GetNewID _ANSI_ARGS_((TkMenuEntry *mePtr, - WORD *menuIDPtr)); -static int TkWinMenuKeyObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -static void MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr)); -static void ReconfigureWindowsMenu _ANSI_ARGS_(( - ClientData clientData)); -static void RecursivelyClearActiveMenu _ANSI_ARGS_(( - TkMenu *menuPtr)); -static void SetDefaults _ANSI_ARGS_((int firstTime)); -static LRESULT CALLBACK TkWinMenuProc _ANSI_ARGS_((HWND hwnd, - UINT message, WPARAM wParam, - LPARAM lParam)); -static LRESULT CALLBACK TkWinEmbeddedMenuProc _ANSI_ARGS_((HWND hwnd, - UINT message, WPARAM wParam, - LPARAM lParam)); - + int *heightPtr); +static int GetNewID(TkMenuEntry *mePtr, WORD *menuIDPtr); +static int TkWinMenuKeyObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[]); +static void MenuSelectEvent(TkMenu *menuPtr); +static void ReconfigureWindowsMenu(ClientData clientData); +static void RecursivelyClearActiveMenu(TkMenu *menuPtr); +static void SetDefaults(int firstTime); +static LRESULT CALLBACK TkWinMenuProc(HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam); +static LRESULT CALLBACK TkWinEmbeddedMenuProc(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); /* *---------------------------------------------------------------------- @@ -200,8 +188,8 @@ GetNewID(mePtr, menuIDPtr) int newEntry; Tcl_HashEntry *commandEntryPtr; WORD returnID; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); WORD curID = tsdPtr->lastCommandID + 1; @@ -209,7 +197,7 @@ GetNewID(mePtr, menuIDPtr) * The following code relies on WORD wrapping when the highest value is * incremented. */ - + while (curID != tsdPtr->lastCommandID) { commandEntryPtr = Tcl_CreateHashEntry(&tsdPtr->commandTable, (char *) curID, &newEntry); @@ -251,12 +239,12 @@ static void FreeID(commandID) WORD commandID; { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&tsdPtr->commandTable, (char *) commandID); - + if (entryPtr != NULL) { Tcl_DeleteHashEntry(entryPtr); } @@ -282,17 +270,17 @@ FreeID(commandID) int TkpNewMenu(menuPtr) - TkMenu *menuPtr; /* The common structure we are making the - * platform structure for. */ + TkMenu *menuPtr; /* The common structure we are making the + * platform structure for. */ { HMENU winMenuHdl; Tcl_HashEntry *hashEntryPtr; int newEntry; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); winMenuHdl = CreatePopupMenu(); - + if (winMenuHdl == NULL) { Tcl_AppendResult(menuPtr->interp, "No more menus can be allocated.", (char *) NULL); @@ -300,12 +288,12 @@ TkpNewMenu(menuPtr) } /* - * We hash all of the HMENU's so that we can get their menu ptrs - * back when dispatch messages. + * We hash all of the HMENU's so that we can get their menu ptrs back when + * dispatch messages. */ - hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->winMenuTable, (char *) winMenuHdl, - &newEntry); + hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->winMenuTable, + (char *) winMenuHdl, &newEntry); Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr); menuPtr->platformData = (TkMenuPlatformData) winMenuHdl; @@ -330,17 +318,17 @@ TkpNewMenu(menuPtr) void TkpDestroyMenu(menuPtr) - TkMenu *menuPtr; /* The common menu structure */ + TkMenu *menuPtr; /* The common menu structure */ { HMENU winMenuHdl = (HMENU) menuPtr->platformData; char *searchName; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { Tcl_CancelIdleCall(ReconfigureWindowsMenu, (ClientData) menuPtr); } - + if (winMenuHdl == NULL) { return; } @@ -348,7 +336,7 @@ TkpDestroyMenu(menuPtr) if (menuPtr->menuFlags & MENU_SYSTEM_MENU) { TkMenuEntry *searchEntryPtr; Tcl_HashTable *tablePtr = TkGetMenuHashTable(menuPtr->interp); - char *menuName = Tcl_GetHashKey(tablePtr, + char *menuName = Tcl_GetHashKey(tablePtr, menuPtr->menuRefPtr->hashEntryPtr); /* @@ -358,29 +346,29 @@ TkpDestroyMenu(menuPtr) */ for (searchEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; - searchEntryPtr != NULL; - searchEntryPtr = searchEntryPtr->nextCascadePtr) { - searchName = Tcl_GetStringFromObj(searchEntryPtr->namePtr, NULL); + searchEntryPtr != NULL; + searchEntryPtr = searchEntryPtr->nextCascadePtr) { + searchName = Tcl_GetString(searchEntryPtr->namePtr); if (strcmp(searchName, menuName) == 0) { Tk_Window parentTopLevelPtr = searchEntryPtr - ->menuPtr->parentTopLevelPtr; + ->menuPtr->parentTopLevelPtr; if (parentTopLevelPtr != NULL) { - GetSystemMenu(TkWinGetWrapperWindow(parentTopLevelPtr), - TRUE); + GetSystemMenu( + TkWinGetWrapperWindow(parentTopLevelPtr), TRUE); } break; } } } else { Tcl_HashEntry *hashEntryPtr; - + /* * Remove the menu from the menu hash table, then destroy the handle. */ - hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, - (char *) winMenuHdl); + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, + (char *) winMenuHdl); if (hashEntryPtr != NULL) { Tcl_DeleteHashEntry(hashEntryPtr); } @@ -411,13 +399,13 @@ TkpDestroyMenu(menuPtr) void TkpDestroyMenuEntry(mePtr) - TkMenuEntry *mePtr; /* The entry to destroy */ + TkMenuEntry *mePtr; /* The entry to destroy */ { TkMenu *menuPtr = mePtr->menuPtr; HMENU winMenuHdl = (HMENU) menuPtr->platformData; if (NULL != winMenuHdl) { - if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { + if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); } @@ -432,9 +420,9 @@ TkpDestroyMenuEntry(mePtr) * 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. + * 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. @@ -465,18 +453,17 @@ GetEntryText(mePtr) strcpy(itemText, "( )"); } else { int i; - char *label = (mePtr->labelPtr == NULL) ? "" - : Tcl_GetStringFromObj(mePtr->labelPtr, NULL); - char *accel = (mePtr->accelPtr == NULL) ? "" - : Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + char *label = (mePtr->labelPtr == NULL) ? "" + : Tcl_GetString(mePtr->labelPtr); + char *accel = (mePtr->accelPtr == NULL) ? "" + : Tcl_GetString(mePtr->accelPtr); CONST char *p, *next; Tcl_DString itemString; /* - * 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. + * 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. */ Tcl_DStringInit(&itemString); @@ -491,7 +478,7 @@ GetEntryText(mePtr) next = Tcl_UtfNext(p); Tcl_DStringAppend(&itemString, p, (int) (next - p)); } - if (mePtr->accelLength > 0) { + if (mePtr->accelLength > 0) { Tcl_DStringAppend(&itemString, "\t", 1); for (p = accel, i = 0; *p != '\0'; i++, p = next) { if (*p == '&') { @@ -500,7 +487,7 @@ GetEntryText(mePtr) next = Tcl_UtfNext(p); Tcl_DStringAppend(&itemString, p, (int) (next - p)); } - } + } itemText = ckalloc(Tcl_DStringLength(&itemString) + 1); strcpy(itemText, Tcl_DStringValue(&itemString)); @@ -520,15 +507,15 @@ GetEntryText(mePtr) * None. * * Side effects: - * Configuration information get set for mePtr; old resources - * get freed, if any need it. + * Configuration information get set for mePtr; old resources get freed, + * if any need it. * *---------------------------------------------------------------------- */ static void ReconfigureWindowsMenu( - ClientData clientData) /* The menu we are rebuilding */ + ClientData clientData) /* The menu we are rebuilding */ { TkMenu *menuPtr = (TkMenu *) clientData; TkMenuEntry *mePtr; @@ -539,7 +526,7 @@ ReconfigureWindowsMenu( UINT itemID; int i, count, systemMenu = 0, base; Tcl_DString translatedText; - + if (NULL == winMenuHdl) { return; } @@ -547,7 +534,6 @@ ReconfigureWindowsMenu( /* * Reconstruct the entire menu. Takes care of nasty system menu and index * problem. - * */ base = (menuPtr->menuFlags & MENU_SYSTEM_MENU) ? 7 : 0; @@ -582,37 +568,37 @@ ReconfigureWindowsMenu( /* * Set enabling and disabling correctly. */ - + if (mePtr->state == ENTRY_DISABLED) { flags |= MF_DISABLED | MF_GRAYED; } - + /* * Set the check mark for check entries and radio entries. */ - + if (((mePtr->type == CHECK_BUTTON_ENTRY) || (mePtr->type == RADIO_BUTTON_ENTRY)) && (mePtr->entryFlags & ENTRY_SELECTED)) { flags |= MF_CHECKED; } - + /* - * Set the SEPARATOR bit for separator entries. This bit is not - * used by our internal drawing functions, but it is used by the - * system when drawing the system menu (we do not draw the system menu - * ourselves). If this bit is not set, separator entries on the system + * Set the SEPARATOR bit for separator entries. This bit is not used + * by our internal drawing functions, but it is used by the system + * when drawing the system menu (we do not draw the system menu + * ourselves). If this bit is not set, separator entries on the system * menu will not be drawn correctly. */ if (mePtr->type == SEPARATOR_ENTRY) { flags |= MF_SEPARATOR; } - + if (mePtr->columnBreak) { flags |= MF_MENUBREAK; } - + itemID = (UINT) mePtr->platformEntryData; if ((mePtr->type == CASCADE_ENTRY) && (mePtr->childMenuRefPtr != NULL) @@ -620,44 +606,45 @@ ReconfigureWindowsMenu( HMENU childMenuHdl = (HMENU) mePtr->childMenuRefPtr->menuPtr ->platformData; if (childMenuHdl != NULL) { - /* - * Win32 draws the popup arrow in the wrong color - * for a disabled cascade menu, so do it by hand. - * Given it is disabled, there's no need for it to - * be connected to its child. + /* + * Win32 draws the popup arrow in the wrong color for a + * disabled cascade menu, so do it by hand. Given it is + * disabled, there's no need for it to be connected to its + * child. */ + if (mePtr->state != ENTRY_DISABLED) { flags |= MF_POPUP; /* - * If the MF_POPUP flag is set, then the id - * is interpreted as the handle of a submenu. + * If the MF_POPUP flag is set, then the id is interpreted + * as the handle of a submenu. */ itemID = (UINT) childMenuHdl; - } + } } - if ((menuPtr->menuType == MENUBAR) + if ((menuPtr->menuType == MENUBAR) && !(mePtr->childMenuRefPtr->menuPtr->menuFlags & MENU_SYSTEM_MENU)) { Tcl_DString ds; TkMenuReferences *menuRefPtr; TkMenu *systemMenuPtr = mePtr->childMenuRefPtr->menuPtr; - + Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, Tk_PathName(menuPtr->masterMenuPtr->tkwin), -1); Tcl_DStringAppend(&ds, ".system", 7); - + menuRefPtr = TkFindMenuReferences(menuPtr->interp, Tcl_DStringValue(&ds)); - + Tcl_DStringFree(&ds); - - if ((menuRefPtr != NULL) + + if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL) && (menuPtr->parentTopLevelPtr != NULL) && (systemMenuPtr->masterMenuPtr == menuRefPtr->menuPtr)) { - HMENU systemMenuHdl = + HMENU systemMenuHdl = (HMENU) systemMenuPtr->platformData; HWND wrapper = TkWinGetWrapperWindow(menuPtr ->parentTopLevelPtr); @@ -665,12 +652,12 @@ ReconfigureWindowsMenu( DestroyMenu(systemMenuHdl); systemMenuHdl = GetSystemMenu(wrapper, FALSE); systemMenuPtr->menuFlags |= MENU_SYSTEM_MENU; - systemMenuPtr->platformData = - (TkMenuPlatformData) systemMenuHdl; - if (!(systemMenuPtr->menuFlags + systemMenuPtr->platformData = + (TkMenuPlatformData) systemMenuHdl; + if (!(systemMenuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { - systemMenuPtr->menuFlags - |= MENU_RECONFIGURE_PENDING; + systemMenuPtr->menuFlags + |= MENU_RECONFIGURE_PENDING; Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) systemMenuPtr); } @@ -694,7 +681,7 @@ ReconfigureWindowsMenu( } - if ((menuPtr->menuType == MENUBAR) + if ((menuPtr->menuType == MENUBAR) && (menuPtr->parentTopLevelPtr != NULL)) { HANDLE bar; bar = TkWinGetWrapperWindow(menuPtr->parentTopLevelPtr); @@ -702,7 +689,7 @@ ReconfigureWindowsMenu( DrawMenuBar(bar); } } - + menuPtr->menuFlags &= ~(MENU_RECONFIGURE_PENDING); } @@ -735,8 +722,8 @@ TkpPostMenu(interp, menuPtr, x, y) POINT point; Tk_Window parentWindow = Tk_Parent(menuPtr->tkwin); int oldServiceMode = Tcl_GetServiceMode(); - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); tsdPtr->inPostMenu++; @@ -755,7 +742,7 @@ TkpPostMenu(interp, menuPtr, x, y) * The post commands could have deleted the menu, which means * we are dead and should go away. */ - + if (menuPtr->tkwin == NULL) { tsdPtr->inPostMenu--; return TCL_OK; @@ -776,7 +763,7 @@ TkpPostMenu(interp, menuPtr, x, y) } Tcl_SetServiceMode(TCL_SERVICE_NONE); - + /* * Make an assumption here. If the right button is down, * then we want to track it. Otherwise, track the left mouse button. @@ -797,7 +784,7 @@ TkpPostMenu(interp, menuPtr, x, y) } } - TrackPopupMenu(winMenuHdl, flags, x, y, 0, + TrackPopupMenu(winMenuHdl, flags, x, y, 0, tsdPtr->menuHWND, &noGoawayRect); Tcl_SetServiceMode(oldServiceMode); @@ -843,7 +830,7 @@ TkpMenuNewEntry(mePtr) menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); } - + mePtr->platformEntryData = (TkMenuPlatformEntryData) commandID; return TCL_OK; @@ -887,11 +874,11 @@ TkWinMenuProc(hwnd, message, wParam, lParam) * * UpdateEmbeddedMenu -- * - * This function is used as work-around for updating the pull-down - * window of an embedded menu which may show as a blank popup window. + * This function is used as work-around for updating the pull-down window + * of an embedded menu which may show as a blank popup window. * * Results: - * Invalidate the client area of the embedded pull-down menu and + * Invalidate the client area of the embedded pull-down menu and * redraw it. * * Side effects: @@ -934,32 +921,37 @@ TkWinEmbeddedMenuProc(hwnd, message, wParam, lParam) { static nIdles = 0; LRESULT lResult = 1; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); switch(message) { - case WM_ENTERIDLE: - if((wParam == MSGF_MENU) && (nIdles < 1) && (hwnd == tsdPtr->embeddedMenuHWND)) { - Tcl_CreateTimerHandler(200, UpdateEmbeddedMenu, (ClientData)lParam); + case WM_ENTERIDLE: + if ((wParam == MSGF_MENU) && (nIdles < 1) + && (hwnd == tsdPtr->embeddedMenuHWND)) { + Tcl_CreateTimerHandler(200, UpdateEmbeddedMenu, + (ClientData) lParam); nIdles++; } break; - - case WM_INITMENUPOPUP: + + case WM_INITMENUPOPUP: nIdles = 0; break; - case WM_INITMENU: - case WM_SYSCOMMAND: - case WM_COMMAND: - case WM_MENUCHAR: - case WM_MEASUREITEM: - case WM_DRAWITEM: - case WM_MENUSELECT: - lResult = TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, &lResult); - if(lResult || (GetCapture() != hwnd)) break; + case WM_INITMENU: + case WM_SYSCOMMAND: + case WM_COMMAND: + case WM_MENUCHAR: + case WM_MEASUREITEM: + case WM_DRAWITEM: + case WM_MENUSELECT: + lResult = TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, + &lResult); + if (lResult || (GetCapture() != hwnd)) { + break; + } - default: + default: lResult = DefWindowProc(hwnd, message, wParam, lParam); break; } @@ -971,17 +963,17 @@ TkWinEmbeddedMenuProc(hwnd, message, wParam, lParam) * * TkWinHandleMenuEvent -- * - * Filters out menu messages from messages passed to a top-level. - * Will respond appropriately to WM_COMMAND, WM_MENUSELECT, - * WM_MEASUREITEM, WM_DRAWITEM + * Filters out menu messages from messages passed to a top-level. Will + * respond appropriately to WM_COMMAND, WM_MENUSELECT, WM_MEASUREITEM, + * WM_DRAWITEM * * Result: * Returns 1 if this handled the message; 0 if it did not. * * Side effects: - * All of the parameters may be modified so that the caller can - * think it is getting a different message. plResult points to - * the result that should be returned to windows from this message. + * All of the parameters may be modified so that the caller can think it + * is getting a different message. plResult points to the result that + * should be returned to windows from this message. * *---------------------------------------------------------------------- */ @@ -998,277 +990,270 @@ TkWinHandleMenuEvent(phwnd, pMessage, pwParam, plParam, plResult) int returnResult = 0; TkMenu *menuPtr; TkMenuEntry *mePtr; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); switch (*pMessage) { - case WM_INITMENU: - TkMenuInit(); - hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, - (char *) *pwParam); - if (hashEntryPtr != NULL) { - tsdPtr->oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); - tsdPtr->modalMenuPtr = menuPtr; - if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { - Tcl_CancelIdleCall(ReconfigureWindowsMenu, - (ClientData) menuPtr); - ReconfigureWindowsMenu((ClientData) menuPtr); - } - RecursivelyClearActiveMenu(menuPtr); - if (!tsdPtr->inPostMenu) { - Tcl_Interp *interp; - int code; - - interp = menuPtr->interp; - Tcl_Preserve((ClientData)interp); - code = TkPreprocessMenu(menuPtr); - if ((code != TCL_OK) && (code != TCL_CONTINUE) - && (code != TCL_BREAK)) { - Tcl_AddErrorInfo(interp, "\n (menu preprocess)"); - Tcl_BackgroundError(interp); - } - Tcl_Release((ClientData)interp); - } - TkActivateMenuEntry(menuPtr, -1); - *plResult = 0; - returnResult = 1; - } else { - tsdPtr->modalMenuPtr = NULL; - } - break; - - case WM_SYSCOMMAND: - case WM_COMMAND: { - TkMenuInit(); - if (HIWORD(*pwParam) != 0) { - break; - } - hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->commandTable, - (char *)LOWORD(*pwParam)); - if (hashEntryPtr == NULL) { - break; + case WM_INITMENU: + TkMenuInit(); + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, + (char *) *pwParam); + if (hashEntryPtr != NULL) { + tsdPtr->oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); + tsdPtr->modalMenuPtr = menuPtr; + if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { + Tcl_CancelIdleCall(ReconfigureWindowsMenu, + (ClientData) menuPtr); + ReconfigureWindowsMenu((ClientData) menuPtr); } - mePtr = (TkMenuEntry *) Tcl_GetHashValue(hashEntryPtr); - if (mePtr != NULL) { - TkMenuReferences *menuRefPtr; - TkMenuEntry *parentEntryPtr; + RecursivelyClearActiveMenu(menuPtr); + if (!tsdPtr->inPostMenu) { Tcl_Interp *interp; int code; - /* - * We have to set the parent of this menu to be active - * if this is a submenu so that tearoffs will get the - * correct title. - */ - - menuPtr = mePtr->menuPtr; - menuRefPtr = TkFindMenuReferences(menuPtr->interp, - Tk_PathName(menuPtr->tkwin)); - if ((menuRefPtr != NULL) - && (menuRefPtr->parentEntryPtr != NULL)) { - char *name; - - for (parentEntryPtr = menuRefPtr->parentEntryPtr; - ; - parentEntryPtr = - parentEntryPtr->nextCascadePtr) { - name = Tcl_GetStringFromObj( - parentEntryPtr->namePtr, NULL); - if (strcmp(name, Tk_PathName(menuPtr->tkwin)) - == 0) { - break; - } - } - if (parentEntryPtr->menuPtr->entries[parentEntryPtr->index] - ->state != ENTRY_DISABLED) { - TkActivateMenuEntry(parentEntryPtr->menuPtr, - parentEntryPtr->index); - } - } - interp = menuPtr->interp; Tcl_Preserve((ClientData)interp); - code = TkInvokeMenu(interp, menuPtr, mePtr->index); - if (code != TCL_OK && code != TCL_CONTINUE - && code != TCL_BREAK) { - Tcl_AddErrorInfo(interp, "\n (menu invoke)"); + code = TkPreprocessMenu(menuPtr); + if ((code != TCL_OK) && (code != TCL_CONTINUE) + && (code != TCL_BREAK)) { + Tcl_AddErrorInfo(interp, "\n (menu preprocess)"); Tcl_BackgroundError(interp); } Tcl_Release((ClientData)interp); - *plResult = 0; - returnResult = 1; } + TkActivateMenuEntry(menuPtr, -1); + *plResult = 0; + returnResult = 1; + } else { + tsdPtr->modalMenuPtr = NULL; + } + break; + + case WM_SYSCOMMAND: + case WM_COMMAND: + TkMenuInit(); + if (HIWORD(*pwParam) != 0) { + break; + } + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->commandTable, + (char *) LOWORD(*pwParam)); + if (hashEntryPtr == NULL) { break; } + mePtr = (TkMenuEntry *) Tcl_GetHashValue(hashEntryPtr); + if (mePtr != NULL) { + TkMenuReferences *menuRefPtr; + TkMenuEntry *parentEntryPtr; + Tcl_Interp *interp; + int code; - case WM_MENUCHAR: { - unsigned char menuChar = (unsigned char) LOWORD(*pwParam); - hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, - (char *) *plParam); - if (hashEntryPtr != NULL) { - int i; + /* + * We have to set the parent of this menu to be active if this is + * a submenu so that tearoffs will get the correct title. + */ - *plResult = 0; - menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); - for (i = 0; i < menuPtr->numEntries; i++) { - int underline; - char *label; - - underline = menuPtr->entries[i]->underline; - if (menuPtr->entries[i]->labelPtr != NULL) { - label = Tcl_GetStringFromObj( - menuPtr->entries[i]->labelPtr, NULL); - } - if ((-1 != underline) - && (NULL != menuPtr->entries[i]->labelPtr) - && (CharUpper((LPTSTR) menuChar) - == CharUpper((LPTSTR) (unsigned char) - label[underline]))) { - *plResult = (2 << 16) | i; - returnResult = 1; + menuPtr = mePtr->menuPtr; + menuRefPtr = TkFindMenuReferences(menuPtr->interp, + Tk_PathName(menuPtr->tkwin)); + if ((menuRefPtr != NULL) && (menuRefPtr->parentEntryPtr != NULL)) { + for (parentEntryPtr = menuRefPtr->parentEntryPtr ; ; + parentEntryPtr = parentEntryPtr->nextCascadePtr) { + char *name = Tcl_GetString(parentEntryPtr->namePtr); + + if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) { break; } } + if (parentEntryPtr->menuPtr->entries[parentEntryPtr->index] + ->state != ENTRY_DISABLED) { + TkActivateMenuEntry(parentEntryPtr->menuPtr, + parentEntryPtr->index); + } } - break; + + interp = menuPtr->interp; + Tcl_Preserve((ClientData)interp); + code = TkInvokeMenu(interp, menuPtr, mePtr->index); + if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { + Tcl_AddErrorInfo(interp, "\n (menu invoke)"); + Tcl_BackgroundError(interp); + } + Tcl_Release((ClientData)interp); + *plResult = 0; + returnResult = 1; } + break; - case WM_MEASUREITEM: { - LPMEASUREITEMSTRUCT itemPtr = (LPMEASUREITEMSTRUCT) *plParam; - - if (itemPtr != NULL && tsdPtr->modalMenuPtr != NULL) { - mePtr = (TkMenuEntry *) itemPtr->itemData; - menuPtr = mePtr->menuPtr; - - TkRecomputeMenu(menuPtr); - itemPtr->itemHeight = mePtr->height; - itemPtr->itemWidth = mePtr->width; - if (mePtr->hideMargin) { - itemPtr->itemWidth += 2 - indicatorDimensions[1]; - } else { - int activeBorderWidth; - - Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, - menuPtr->activeBorderWidthPtr, - &activeBorderWidth); - itemPtr->itemWidth += 2 * activeBorderWidth; + case WM_MENUCHAR: { + unsigned char menuChar = (unsigned char) LOWORD(*pwParam); + + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, + (char *) *plParam); + if (hashEntryPtr != NULL) { + int i; + + *plResult = 0; + menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); + for (i = 0; i < menuPtr->numEntries; i++) { + int underline; + char *label; + + underline = menuPtr->entries[i]->underline; + if (menuPtr->entries[i]->labelPtr != NULL) { + label = Tcl_GetString(menuPtr->entries[i]->labelPtr); + } + if ((-1 != underline) + && (NULL != menuPtr->entries[i]->labelPtr) + && (CharUpper((LPTSTR) menuChar) + == CharUpper((LPTSTR) UCHAR(label[underline])))) { + *plResult = (2 << 16) | i; + returnResult = 1; + break; } - *plResult = 1; - returnResult = 1; } - break; } - - case WM_DRAWITEM: { - TkWinDrawable *twdPtr; - LPDRAWITEMSTRUCT itemPtr = (LPDRAWITEMSTRUCT) *plParam; - Tk_FontMetrics fontMetrics; - int drawArrow = 0; - - if (itemPtr != NULL && tsdPtr->modalMenuPtr != NULL) { - Tk_Font tkfont; - - mePtr = (TkMenuEntry *) itemPtr->itemData; - menuPtr = mePtr->menuPtr; - twdPtr = (TkWinDrawable *) ckalloc(sizeof(TkWinDrawable)); - twdPtr->type = TWD_WINDC; - twdPtr->winDC.hdc = itemPtr->hDC; + break; + } - if (mePtr->state != ENTRY_DISABLED) { - if (itemPtr->itemState & ODS_SELECTED) { - TkActivateMenuEntry(menuPtr, mePtr->index); - } else { - TkActivateMenuEntry(menuPtr, -1); - } - } else { - /* On windows, menu entries should highlight even if they - ** are disabled. (I know this seems dumb, but it is the way - ** native windows menus works so we ought to mimic it.) - ** The ENTRY_PLATFORM_FLAG1 flag will indicate that the - ** entry should be highlighted even though it is disabled. - */ - if (itemPtr->itemState & ODS_SELECTED) { - mePtr->entryFlags |= ENTRY_PLATFORM_FLAG1; - } else { - mePtr->entryFlags &= ~ENTRY_PLATFORM_FLAG1; - } - /* Also, set the drawArrow flag for a disabled cascade - ** menu since we need to draw the arrow ourselves. - */ - if (mePtr->type == CASCADE_ENTRY) { - drawArrow = 1; - } - } + case WM_MEASUREITEM: { + LPMEASUREITEMSTRUCT itemPtr = (LPMEASUREITEMSTRUCT) *plParam; - tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); - Tk_GetFontMetrics(tkfont, &fontMetrics); - TkpDrawMenuEntry(mePtr, (Drawable) twdPtr, tkfont, - &fontMetrics, itemPtr->rcItem.left, - itemPtr->rcItem.top, itemPtr->rcItem.right - - itemPtr->rcItem.left, itemPtr->rcItem.bottom - - itemPtr->rcItem.top, 0, drawArrow); + if (itemPtr != NULL && tsdPtr->modalMenuPtr != NULL) { + mePtr = (TkMenuEntry *) itemPtr->itemData; + menuPtr = mePtr->menuPtr; - ckfree((char *) twdPtr); + TkRecomputeMenu(menuPtr); + itemPtr->itemHeight = mePtr->height; + itemPtr->itemWidth = mePtr->width; + if (mePtr->hideMargin) { + itemPtr->itemWidth += 2 - indicatorDimensions[1]; + } else { + int activeBorderWidth; + + Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, + menuPtr->activeBorderWidthPtr, &activeBorderWidth); + itemPtr->itemWidth += 2 * activeBorderWidth; } - *plResult = 1; + *plResult = 1; returnResult = 1; - break; } + break; + } + + case WM_DRAWITEM: { + TkWinDrawable *twdPtr; + LPDRAWITEMSTRUCT itemPtr = (LPDRAWITEMSTRUCT) *plParam; + Tk_FontMetrics fontMetrics; + int drawArrow = 0; - case WM_MENUSELECT: { - UINT flags = HIWORD(*pwParam); + if (itemPtr != NULL && tsdPtr->modalMenuPtr != NULL) { + Tk_Font tkfont; - TkMenuInit(); + mePtr = (TkMenuEntry *) itemPtr->itemData; + menuPtr = mePtr->menuPtr; + twdPtr = (TkWinDrawable *) ckalloc(sizeof(TkWinDrawable)); + twdPtr->type = TWD_WINDC; + twdPtr->winDC.hdc = itemPtr->hDC; - if ((flags == 0xFFFF) && (*plParam == 0)) { - if (tsdPtr->modalMenuPtr != NULL) { - Tcl_SetServiceMode(tsdPtr->oldServiceMode); - RecursivelyClearActiveMenu(tsdPtr->modalMenuPtr); + if (mePtr->state != ENTRY_DISABLED) { + if (itemPtr->itemState & ODS_SELECTED) { + TkActivateMenuEntry(menuPtr, mePtr->index); + } else { + TkActivateMenuEntry(menuPtr, -1); } } else { - menuPtr = NULL; - if (*plParam != 0) { - hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, - (char *) *plParam); - if (hashEntryPtr != NULL) { - menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); - } + /* + * On windows, menu entries should highlight even if they are + * disabled. (I know this seems dumb, but it is the way native + * windows menus works so we ought to mimic it.) The + * ENTRY_PLATFORM_FLAG1 flag will indicate that the entry + * should be highlighted even though it is disabled. + */ + + if (itemPtr->itemState & ODS_SELECTED) { + mePtr->entryFlags |= ENTRY_PLATFORM_FLAG1; + } else { + mePtr->entryFlags &= ~ENTRY_PLATFORM_FLAG1; } - if (menuPtr != NULL) { - long entryIndex = LOWORD(*pwParam); - mePtr = NULL; - if (flags != 0xFFFF) { - if ((flags & MF_POPUP) && (entryIndex < menuPtr->numEntries)) { - mePtr = menuPtr->entries[entryIndex]; - } else { - hashEntryPtr = Tcl_FindHashEntry( - &tsdPtr->commandTable, - (char *) entryIndex); - if (hashEntryPtr != NULL) { - mePtr = (TkMenuEntry *) - Tcl_GetHashValue(hashEntryPtr); - } - } - } + /* + * Also, set the drawArrow flag for a disabled cascade menu + * since we need to draw the arrow ourselves. + */ + + if (mePtr->type == CASCADE_ENTRY) { + drawArrow = 1; + } + } + + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(tkfont, &fontMetrics); + TkpDrawMenuEntry(mePtr, (Drawable) twdPtr, tkfont, &fontMetrics, + itemPtr->rcItem.left, itemPtr->rcItem.top, + itemPtr->rcItem.right - itemPtr->rcItem.left, + itemPtr->rcItem.bottom - itemPtr->rcItem.top, 0,drawArrow); + + ckfree((char *) twdPtr); + } + *plResult = 1; + returnResult = 1; + break; + } + + case WM_MENUSELECT: { + UINT flags = HIWORD(*pwParam); + + TkMenuInit(); - if ((mePtr == NULL) || (mePtr->state == ENTRY_DISABLED)) { - TkActivateMenuEntry(menuPtr, -1); + if ((flags == 0xFFFF) && (*plParam == 0)) { + if (tsdPtr->modalMenuPtr != NULL) { + Tcl_SetServiceMode(tsdPtr->oldServiceMode); + RecursivelyClearActiveMenu(tsdPtr->modalMenuPtr); + } + } else { + menuPtr = NULL; + if (*plParam != 0) { + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, + (char *) *plParam); + if (hashEntryPtr != NULL) { + menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); + } + } + + if (menuPtr != NULL) { + long entryIndex = LOWORD(*pwParam); + + mePtr = NULL; + if (flags != 0xFFFF) { + if ((flags&MF_POPUP) && (entryIndex<menuPtr->numEntries)) { + mePtr = menuPtr->entries[entryIndex]; } else { - if (mePtr->index >= menuPtr->numEntries) { - Tcl_Panic("Trying to activate an entry which doesn't exist."); + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->commandTable, + (char *) entryIndex); + if (hashEntryPtr != NULL) { + mePtr = (TkMenuEntry *) + Tcl_GetHashValue(hashEntryPtr); } - TkActivateMenuEntry(menuPtr, mePtr->index); } - MenuSelectEvent(menuPtr); - Tcl_ServiceAll(); - *plResult = 0; - returnResult = 1; } + + if ((mePtr == NULL) || (mePtr->state == ENTRY_DISABLED)) { + TkActivateMenuEntry(menuPtr, -1); + } else { + if (mePtr->index >= menuPtr->numEntries) { + Tcl_Panic("Trying to activate an entry which doesn't exist."); + } + TkActivateMenuEntry(menuPtr, mePtr->index); + } + MenuSelectEvent(menuPtr); + Tcl_ServiceAll(); + *plResult = 0; + returnResult = 1; } - break; } + break; + } } return returnResult; } @@ -1295,7 +1280,7 @@ RecursivelyClearActiveMenu( { int i; TkMenuEntry *mePtr; - + TkActivateMenuEntry(menuPtr, -1); MenuSelectEvent(menuPtr); for (i = 0; i < menuPtr->numEntries; i++) { @@ -1332,25 +1317,26 @@ RecursivelyClearActiveMenu( void TkpSetWindowMenuBar(tkwin, menuPtr) - Tk_Window tkwin; /* The window we are putting the menubar into.*/ - TkMenu *menuPtr; /* The menu we are inserting */ + Tk_Window tkwin; /* The window we are putting the menubar + * into.*/ + TkMenu *menuPtr; /* The menu we are inserting */ { HMENU winMenuHdl; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (menuPtr != NULL) { Tcl_HashEntry *hashEntryPtr; int newEntry; winMenuHdl = (HMENU) menuPtr->platformData; - hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, - (char *) winMenuHdl); + hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, + (char *) winMenuHdl); Tcl_DeleteHashEntry(hashEntryPtr); DestroyMenu(winMenuHdl); winMenuHdl = CreateMenu(); - hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->winMenuTable, - (char *) winMenuHdl, &newEntry); + hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->winMenuTable, + (char *) winMenuHdl, &newEntry); Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr); menuPtr->platformData = (TkMenuPlatformData) winMenuHdl; TkWinSetMenu(tkwin, winMenuHdl); @@ -1368,8 +1354,8 @@ TkpSetWindowMenuBar(tkwin, menuPtr) * * TkpSetMainMenubar -- * - * Puts the menu associated with a window into the menubar. Should - * only be called when the window is in front. + * Puts the menu associated with a window into the menubar. Should only + * be called when the window is in front. * * Results: * None. @@ -1379,13 +1365,13 @@ TkpSetWindowMenuBar(tkwin, menuPtr) * *---------------------------------------------------------------------- */ + void TkpSetMainMenubar( Tcl_Interp *interp, /* The interpreter of the application */ Tk_Window tkwin, /* The frame we are setting up */ - char *menuName) /* The name of the menu to put in front. - * If NULL, use the default menu bar. - */ + char *menuName) /* The name of the menu to put in front. If + * NULL, use the default menu bar. */ { /* * Nothing to do. @@ -1410,12 +1396,12 @@ TkpSetMainMenubar( void GetMenuIndicatorGeometry ( - TkMenu *menuPtr, /* The menu we are measuring */ - TkMenuEntry *mePtr, /* The entry we are measuring */ - Tk_Font tkfont, /* Precalculated font */ - CONST Tk_FontMetrics *fmPtr, /* Precalculated font metrics */ - int *widthPtr, /* The resulting width */ - int *heightPtr) /* The resulting height */ + TkMenu *menuPtr, /* The menu we are measuring */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* Precalculated font */ + CONST Tk_FontMetrics *fmPtr,/* Precalculated font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ { *heightPtr = indicatorDimensions[0]; if (mePtr->hideMargin) { @@ -1447,12 +1433,12 @@ GetMenuIndicatorGeometry ( void GetMenuAccelGeometry ( - TkMenu *menuPtr, /* The menu we are measuring */ - TkMenuEntry *mePtr, /* The entry we are measuring */ - Tk_Font tkfont, /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ - int *widthPtr, /* The resulting width */ - int *heightPtr) /* The resulting height */ + TkMenu *menuPtr, /* The menu we are measuring */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ { *heightPtr = fmPtr->linespace; if (mePtr->type == CASCADE_ENTRY) { @@ -1460,7 +1446,8 @@ GetMenuAccelGeometry ( } else if (mePtr->accelPtr == NULL) { *widthPtr = 0; } else { - char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + char *accel = Tcl_GetString(mePtr->accelPtr); + *widthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength); } } @@ -1483,12 +1470,12 @@ GetMenuAccelGeometry ( void GetTearoffEntryGeometry ( - TkMenu *menuPtr, /* The menu we are measuring */ - TkMenuEntry *mePtr, /* The entry we are measuring */ - Tk_Font tkfont, /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ - int *widthPtr, /* The resulting width */ - int *heightPtr) /* The resulting height */ + TkMenu *menuPtr, /* The menu we are measuring */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ { if (menuPtr->menuType != MASTER_MENU) { *heightPtr = 0; @@ -1516,12 +1503,12 @@ GetTearoffEntryGeometry ( void GetMenuSeparatorGeometry ( - TkMenu *menuPtr, /* The menu we are measuring */ - TkMenuEntry *mePtr, /* The entry we are measuring */ - Tk_Font tkfont, /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr, /* The precalcualted font metrics */ - int *widthPtr, /* The resulting width */ - int *heightPtr) /* The resulting height */ + TkMenu *menuPtr, /* The menu we are measuring */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr,/* The precalcualted font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ { *widthPtr = 0; *heightPtr = fmPtr->linespace - (2 * fmPtr->descent); @@ -1532,10 +1519,10 @@ GetMenuSeparatorGeometry ( * * DrawWindowsSystemBitmap -- * - * Draws the windows system bitmap given by bitmapID into the rect - * given by rectPtr in the drawable. The bitmap is centered in the - * rectangle. It is not clipped, so if the bitmap is bigger than - * the rect it will bleed. + * Draws the windows system bitmap given by bitmapID into the rect given + * by rectPtr in the drawable. The bitmap is centered in the rectangle. + * It is not clipped, so if the bitmap is bigger than the rect it will + * bleed. * * Results: * None. @@ -1548,14 +1535,14 @@ GetMenuSeparatorGeometry ( static void DrawWindowsSystemBitmap(display, drawable, gc, rectPtr, bitmapID, alignFlags) - Display *display; /* The display we are drawing into */ - Drawable drawable; /* The drawable we are working with */ - GC gc; /* The GC to draw with */ - CONST RECT *rectPtr; /* The rectangle to draw into */ - int bitmapID; /* The windows id of the system - * bitmap to draw. */ - int alignFlags; /* How to align the bitmap inside the - * rectangle. */ + Display *display; /* The display we are drawing into */ + Drawable drawable; /* The drawable we are working with */ + GC gc; /* The GC to draw with */ + CONST RECT *rectPtr; /* The rectangle to draw into */ + int bitmapID; /* The windows id of the system bitmap to + * draw. */ + int alignFlags; /* How to align the bitmap inside the + * rectangle. */ { TkWinDCState state; HDC hdc = TkWinGetDrawableDC(display, drawable, &state); @@ -1565,7 +1552,7 @@ DrawWindowsSystemBitmap(display, drawable, gc, rectPtr, bitmapID, alignFlags) POINT ptSize; POINT ptOrg; int topOffset, leftOffset; - + SetBkColor(hdc, gc->background); SetTextColor(hdc, gc->foreground); @@ -1597,7 +1584,7 @@ DrawWindowsSystemBitmap(display, drawable, gc, rectPtr, bitmapID, alignFlags) } else { leftOffset = (rectPtr->right - rectPtr->left) / 2 - (ptSize.x / 2); } - + BitBlt(hdc, rectPtr->left + leftOffset, rectPtr->top + topOffset, ptSize.x, ptSize.y, scratchDC, ptOrg.x, ptOrg.y, SRCCOPY); DeleteDC(scratchDC); @@ -1611,38 +1598,39 @@ DrawWindowsSystemBitmap(display, drawable, gc, rectPtr, bitmapID, alignFlags) * * DrawMenuEntryIndicator -- * - * This procedure draws the indicator part of a menu. + * This function draws the indicator part of a menu. * * Results: * None. * * Side effects: - * Commands are output to X to display the menu in its - * current mode. + * Commands are output to X to display the menu in its current mode. * *---------------------------------------------------------------------- */ + void DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x, y, width, height) - TkMenu *menuPtr; /* The menu we are drawing */ - TkMenuEntry *mePtr; /* The entry we are drawing */ - Drawable d; /* What we are drawing into */ - GC gc; /* The gc we are drawing with */ - GC indicatorGC; /* The gc for indicator objects */ - Tk_Font tkfont; /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */ - int x; /* Left edge */ - int y; /* Top edge */ + TkMenu *menuPtr; /* The menu we are drawing */ + TkMenuEntry *mePtr; /* The entry we are drawing */ + Drawable d; /* What we are drawing into */ + GC gc; /* The gc we are drawing with */ + GC indicatorGC; /* The gc for indicator objects */ + Tk_Font tkfont; /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */ + int x; /* Left edge */ + int y; /* Top edge */ int width; int height; { - if ((mePtr->type == CHECK_BUTTON_ENTRY) + if ((mePtr->type == CHECK_BUTTON_ENTRY) || (mePtr->type == RADIO_BUTTON_ENTRY)) { if (mePtr->indicatorOn && (mePtr->entryFlags & ENTRY_SELECTED)) { RECT rect; GC whichGC; int borderWidth, activeBorderWidth; + if (mePtr->state != ENTRY_NORMAL) { whichGC = gc; } else { @@ -1662,21 +1650,21 @@ DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x, && (menuPtr->disabledFgPtr != NULL)) { RECT hilightRect; COLORREF oldFgColor = whichGC->foreground; - + whichGC->foreground = GetSysColor(COLOR_3DHILIGHT); hilightRect.top = rect.top + 1; hilightRect.bottom = rect.bottom + 1; hilightRect.left = rect.left + 1; hilightRect.right = rect.right + 1; - DrawWindowsSystemBitmap(menuPtr->display, d, whichGC, + DrawWindowsSystemBitmap(menuPtr->display, d, whichGC, &hilightRect, OBM_CHECK, 0); whichGC->foreground = oldFgColor; } - DrawWindowsSystemBitmap(menuPtr->display, d, whichGC, &rect, + DrawWindowsSystemBitmap(menuPtr->display, d, whichGC, &rect, OBM_CHECK, 0); } - } + } } /* @@ -1684,11 +1672,10 @@ DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x, * * DrawMenuEntryAccelerator -- * - * This procedure draws the accelerator part of a menu. - * For example, the string "CTRL-Z" could be drawn to - * to the right of the label text for an Undo menu entry. - * Need to decide what to draw here. Should we replace strings - * like "Control", "Command", etc? + * This function draws the accelerator part of a menu. For example, the + * string "CTRL-Z" could be drawn to to the right of the label text for + * an Undo menu entry. Need to decide what to draw here. Should we + * replace strings like "Control", "Command", etc? * * Results: * None. @@ -1701,49 +1688,52 @@ DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x, */ void -DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, - activeBorder, x, y, width, height) - TkMenu *menuPtr; /* The menu we are drawing */ - TkMenuEntry *mePtr; /* The entry we are drawing */ - Drawable d; /* What we are drawing into */ - GC gc; /* The gc we are drawing with */ - Tk_Font tkfont; /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */ - Tk_3DBorder activeBorder; /* The border when an item is active */ - int x; /* left edge */ - int y; /* top edge */ - int width; /* Width of menu entry */ - int height; /* Height of menu entry */ +DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder, + x, y, width, height) + TkMenu *menuPtr; /* The menu we are drawing */ + TkMenuEntry *mePtr; /* The entry we are drawing */ + Drawable d; /* What we are drawing into */ + GC gc; /* The gc we are drawing with */ + Tk_Font tkfont; /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */ + Tk_3DBorder activeBorder; /* The border when an item is active */ + int x; /* left edge */ + int y; /* top edge */ + int width; /* Width of menu entry */ + int height; /* Height of menu entry */ { int baseline; int leftEdge = x + mePtr->indicatorSpace + mePtr->labelWidth; char *accel; - + if (mePtr->accelPtr != NULL) { - accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + accel = Tcl_GetString(mePtr->accelPtr); } baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; - /* Draw disabled 3D text highlight only with the Win95/98 look. */ + /* + * Draw disabled 3D text highlight only with the Win95/98 look. + */ if (TkWinGetPlatformTheme() == TK_THEME_WIN_CLASSIC) { - if ((mePtr->state == ENTRY_DISABLED) && (menuPtr->disabledFgPtr != NULL) - && (mePtr->accelPtr != NULL)) { + if ((mePtr->state == ENTRY_DISABLED) + && (menuPtr->disabledFgPtr != NULL) + && (mePtr->accelPtr != NULL)) { COLORREF oldFgColor = gc->foreground; gc->foreground = GetSysColor(COLOR_3DHILIGHT); if ((mePtr->accelPtr != NULL) && - ((mePtr->entryFlags & ENTRY_PLATFORM_FLAG1) == 0)) { - Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, - mePtr->accelLength, leftEdge + 1, baseline + 1); + ((mePtr->entryFlags & ENTRY_PLATFORM_FLAG1) == 0)) { + Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, + mePtr->accelLength, leftEdge + 1, baseline + 1); } gc->foreground = oldFgColor; } } if (mePtr->accelPtr != NULL) { - Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, + Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, mePtr->accelLength, leftEdge, baseline); } } @@ -1753,8 +1743,8 @@ DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, * * DrawMenuEntryArrow -- * - * This function draws the arrow bitmap on the right side of a - * a menu entry. This function is currently unused. + * This function draws the arrow bitmap on the right side of a menu + * entry. This function is currently unused. * * Results: * None. @@ -1766,41 +1756,43 @@ DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, */ void -DrawMenuEntryArrow(menuPtr, mePtr, d, gc, - activeBorder, x, y, width, height, drawArrow) - TkMenu *menuPtr; /* The menu we are drawing */ - TkMenuEntry *mePtr; /* The entry we are drawing */ - Drawable d; /* What we are drawing into */ - GC gc; /* The gc we are drawing with */ - Tk_3DBorder activeBorder; /* The border when an item is active */ - int x; /* left edge */ - int y; /* top edge */ - int width; /* Width of menu entry */ - int height; /* Height of menu entry */ - int drawArrow; /* For cascade menus, whether of not - * to draw the arraw. I cannot figure - * out Windows' algorithm for where - * to draw this. */ +DrawMenuEntryArrow(menuPtr, mePtr, d, gc, activeBorder, x, y, width, height, + drawArrow) + TkMenu *menuPtr; /* The menu we are drawing */ + TkMenuEntry *mePtr; /* The entry we are drawing */ + Drawable d; /* What we are drawing into */ + GC gc; /* The gc we are drawing with */ + Tk_3DBorder activeBorder; /* The border when an item is active */ + int x; /* left edge */ + int y; /* top edge */ + int width; /* Width of menu entry */ + int height; /* Height of menu entry */ + int drawArrow; /* For cascade menus, whether of not to draw + * the arraw. I cannot figure out Windows' + * algorithm for where to draw this. */ { COLORREF oldFgColor; COLORREF oldBgColor; RECT rect; - if (!drawArrow || (mePtr->type != CASCADE_ENTRY) || - (mePtr->state != ENTRY_DISABLED)) - return; + if (!drawArrow || (mePtr->type != CASCADE_ENTRY) + || (mePtr->state != ENTRY_DISABLED)) { + return; + } oldFgColor = gc->foreground; oldBgColor = gc->background; - /* Set bitmap bg to highlight color if the menu is highlighted */ + /* + * Set bitmap bg to highlight color if the menu is highlighted. + */ + if (mePtr->entryFlags & ENTRY_PLATFORM_FLAG1) { - XColor *activeBgColor = Tk_3DBorderColor(Tk_Get3DBorderFromObj( - mePtr->menuPtr->tkwin, - (mePtr->activeBorderPtr == NULL) ? - mePtr->menuPtr->activeBorderPtr : - mePtr->activeBorderPtr)); - gc->background = activeBgColor->pixel; + XColor *activeBgColor = Tk_3DBorderColor(Tk_Get3DBorderFromObj( + mePtr->menuPtr->tkwin, (mePtr->activeBorderPtr == NULL) + ? mePtr->menuPtr->activeBorderPtr + : mePtr->activeBorderPtr)); + gc->background = activeBgColor->pixel; } gc->foreground = GetSysColor(COLOR_GRAYTEXT); @@ -1811,7 +1803,7 @@ DrawMenuEntryArrow(menuPtr, mePtr, d, gc, rect.right = x + width; DrawWindowsSystemBitmap(menuPtr->display, d, gc, &rect, OBM_MNARROW, - ALIGN_BITMAP_RIGHT); + ALIGN_BITMAP_RIGHT); gc->foreground = oldFgColor; gc->background = oldBgColor; @@ -1829,23 +1821,23 @@ DrawMenuEntryArrow(menuPtr, mePtr, d, gc, * None. * * Side effects: - * Commands are output to X to display the menu in its - * current mode. + * Commands are output to X to display the menu in its current mode. * *---------------------------------------------------------------------- */ + void DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) - TkMenu *menuPtr; /* The menu we are drawing */ - TkMenuEntry *mePtr; /* The entry we are drawing */ - Drawable d; /* What we are drawing into */ - GC gc; /* The gc we are drawing with */ - Tk_Font tkfont; /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */ - int x; /* left edge */ - int y; /* top edge */ - int width; /* width of item */ - int height; /* height of item */ + TkMenu *menuPtr; /* The menu we are drawing */ + TkMenuEntry *mePtr; /* The entry we are drawing */ + Drawable d; /* What we are drawing into */ + GC gc; /* The gc we are drawing with */ + Tk_Font tkfont; /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */ + int x; /* left edge */ + int y; /* top edge */ + int width; /* width of item */ + int height; /* height of item */ { XPoint points[2]; Tk_3DBorder border; @@ -1855,7 +1847,7 @@ DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) points[1].x = x + width - 1; points[1].y = points[0].y; border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); - Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, + Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, TK_RELIEF_RAISED); } @@ -1864,41 +1856,40 @@ DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) * * DrawMenuUnderline -- * - * On appropriate platforms, draw the underline character for the - * menu. + * On appropriate platforms, draw the underline character for the menu. * * Results: * None. * * Side effects: - * Commands are output to X to display the menu in its - * current mode. + * Commands are output to X to display the menu in its current mode. * *---------------------------------------------------------------------- */ + static void DrawMenuUnderline( - TkMenu *menuPtr, /* The menu to draw into */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* What we are drawing into */ - GC gc, /* The gc to draw into */ - Tk_Font tkfont, /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ - int x, /* Left Edge */ - int y, /* Top Edge */ - int width, /* Width of entry */ - int height) /* Height of entry */ + TkMenu *menuPtr, /* The menu to draw into */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* What we are drawing into */ + GC gc, /* The gc to draw into */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ + int x, /* Left Edge */ + int y, /* Top Edge */ + int width, /* Width of entry */ + int height) /* Height of entry */ { if (mePtr->underline >= 0) { - char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + char *label = Tcl_GetString(mePtr->labelPtr); CONST char *start = Tcl_UtfAtIndex(label, mePtr->underline); CONST char *end = Tcl_UtfNext(start); Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, label, x + mePtr->indicatorSpace, - y + (height + fmPtr->ascent - fmPtr->descent) / 2, + y + (height + fmPtr->ascent - fmPtr->descent) / 2, (int) (start - label), (int) (end - label)); - } + } } /* @@ -1906,17 +1897,16 @@ DrawMenuUnderline( * * TkWinMenuKeyObjCmd -- * - * This procedure is invoked when keys related to pulling - * down menus is pressed. The corresponding Windows events - * are generated and passed to DefWindowProc if appropriate. - * This cmd is registered as tk::WinMenuKey in the interp. + * This function is invoked when keys related to pulling down menus is + * pressed. The corresponding Windows events are generated and passed to + * DefWindowProc if appropriate. This cmd is registered as tk::WinMenuKey + * in the interp. * * Results: * Always returns TCL_OK. * * Side effects: - * The menu system may take over and process user events - * for menu input. + * The menu system may take over and process user events for menu input. * *-------------------------------------------------------------- */ @@ -1948,13 +1938,13 @@ TkWinMenuKeyObjCmd(clientData, interp, objc, objv) Tk_MainWindow(interp)); if (tkwin == NULL) { - return TCL_ERROR; + return TCL_ERROR; } winPtr = (TkWindow *)tkwin; if (Tcl_GetIntFromObj(interp, objv[2], &i) != TCL_OK) { - return TCL_ERROR; + return TCL_ERROR; } keySym = i; @@ -1963,8 +1953,7 @@ TkWinMenuKeyObjCmd(clientData, interp, objc, objv) case XK_Alt_L: scanCode = MapVirtualKey(VK_LMENU, 0); CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), - WM_SYSKEYDOWN, VK_MENU, (scanCode << 16) - | (1 << 29)); + WM_SYSKEYDOWN, VK_MENU, (scanCode << 16) | (1 << 29)); break; case XK_Alt_R: scanCode = MapVirtualKey(VK_RMENU, 0); @@ -1987,8 +1976,7 @@ TkWinMenuKeyObjCmd(clientData, interp, objc, objv) if (eventPtr->xkey.nbytes > 0) { for (i = 0; i < eventPtr->xkey.nbytes; i++) { CallWindowProc(DefWindowProc, - Tk_GetHWND(Tk_WindowId(tkwin)), - WM_SYSCHAR, + Tk_GetHWND(Tk_WindowId(tkwin)), WM_SYSCHAR, eventPtr->xkey.trans_chars[i], ((scanCode << 16) | (1 << 29))); } @@ -2033,86 +2021,63 @@ TkWinMenuKeyObjCmd(clientData, interp, objc, objv) * * TkpInitializeMenuBindings -- * - * For every interp, initializes the bindings for Windows - * menus. Does nothing on Mac or XWindows. + * For every interp, initializes the bindings for Windows menus. Does + * nothing on Mac or XWindows. * * Results: * None. * * Side effects: - * bindings are setup for the interp which will - * handle Alt-key sequences for menus without beeping - * or interfering with user-defined Alt-key bindings. + * bindings are setup for the interp which will handle Alt-key sequences + * for menus without beeping or interfering with user-defined Alt-key + * bindings. * *-------------------------------------------------------------- */ void TkpInitializeMenuBindings(interp, bindingTable) - Tcl_Interp *interp; /* The interpreter to set. */ - Tk_BindingTable bindingTable; /* The table to add to. */ + Tcl_Interp *interp; /* The interpreter to set. */ + Tk_BindingTable bindingTable; + /* The table to add to. */ { Tk_Uid uid = Tk_GetUid("all"); /* - * We need to set up the bindings for menubars. These have to - * recreate windows events, so we need to invoke C code to - * generate the WM_SYSKEYDOWNS and WM_SYSKEYUPs appropriately. - * Trick is, we can't create a C level binding directly since - * we may want to modify the binding in Tcl code. + * We need to set up the bindings for menubars. These have to recreate + * windows events, so we need to invoke C code to generate the + * WM_SYSKEYDOWNS and WM_SYSKEYUPs appropriately. Trick is, we can't + * create a C level binding directly since we may want to modify the + * binding in Tcl code. */ (void) Tcl_CreateObjCommand(interp, "tk::WinMenuKey", TkWinMenuKeyObjCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<Alt_L>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<KeyRelease-Alt_L>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<Alt_R>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<KeyRelease-Alt_R>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<Alt-KeyPress>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<Alt-KeyRelease>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<KeyPress-F10>", - "tk::WinMenuKey %W %N", - 0); - - (void) Tk_CreateBinding(interp, bindingTable, - (ClientData) uid, - "<KeyRelease-F10>", - "tk::WinMenuKey %W %N", - 0); + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<Alt_L>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<KeyRelease-Alt_L>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<Alt_R>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<KeyRelease-Alt_R>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<Alt-KeyPress>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<Alt-KeyRelease>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<KeyPress-F10>", "tk::WinMenuKey %W %N", 0); + + (void) Tk_CreateBinding(interp, bindingTable, (ClientData) uid, + "<KeyRelease-F10>", "tk::WinMenuKey %W %N", 0); } /* @@ -2120,7 +2085,7 @@ TkpInitializeMenuBindings(interp, bindingTable) * * DrawMenuEntryLabel -- * - * This procedure draws the label part of a menu. + * This function draws the label part of a menu. * * Results: * None. @@ -2131,20 +2096,21 @@ TkpInitializeMenuBindings(interp, bindingTable) * *---------------------------------------------------------------------- */ + static void DrawMenuEntryLabel( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* What we are drawing into */ - GC gc, /* The gc we are drawing into */ - Tk_Font tkfont, /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ - int x, /* left edge */ - int y, /* right edge */ - int width, /* width of entry */ - int height) /* height of entry */ + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* What we are drawing into */ + GC gc, /* The gc we are drawing into */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ + int x, /* left edge */ + int y, /* right edge */ + int width, /* width of entry */ + int height) /* height of entry */ { - int indicatorSpace = mePtr->indicatorSpace; + int indicatorSpace = mePtr->indicatorSpace; int activeBorderWidth; int leftEdge; int imageHeight, imageWidth; @@ -2163,21 +2129,22 @@ DrawMenuEntryLabel( if (mePtr->image != NULL) { Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight); - haveImage = 1; + haveImage = 1; } else if (mePtr->bitmapPtr != NULL) { Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); Tk_SizeOfBitmap(menuPtr->display, bitmap, &imageWidth, &imageHeight); haveImage = 1; } if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { - if (mePtr->labelLength > 0) { - char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + if (mePtr->labelLength > 0) { + char *label = Tcl_GetString(mePtr->labelPtr); + textWidth = Tk_TextWidth(tkfont, label, mePtr->labelLength); textHeight = fmPtr->linespace; haveText = 1; - } + } } - + /* * Now work out what the relative positions are. */ @@ -2185,56 +2152,53 @@ DrawMenuEntryLabel( if (haveImage && haveText) { int fullWidth = (imageWidth > textWidth ? imageWidth : textWidth); switch ((enum compound) mePtr->compound) { - case COMPOUND_TOP: { - textXOffset = (fullWidth - textWidth)/2; - textYOffset = imageHeight/2 + 2; - imageXOffset = (fullWidth - imageWidth)/2; - imageYOffset = -textHeight/2; - break; - } - case COMPOUND_BOTTOM: { - textXOffset = (fullWidth - textWidth)/2; - textYOffset = -imageHeight/2; - imageXOffset = (fullWidth - imageWidth)/2; - imageYOffset = textHeight/2 + 2; - break; - } - case COMPOUND_LEFT: { - /* - * The standard image position on Windows is in the indicator - * space to the left of the entries, unless this entry is a - * radio|check button because then the indicator space will - * be used. - */ - textXOffset = imageWidth + 2; - textYOffset = 0; - imageXOffset = 0; - imageYOffset = 0; - if ((mePtr->type != CHECK_BUTTON_ENTRY) - && (mePtr->type != RADIO_BUTTON_ENTRY)) { - textXOffset -= indicatorSpace; - if (textXOffset < 0) { - textXOffset = 0; - } - imageXOffset = -indicatorSpace; + case COMPOUND_TOP: + textXOffset = (fullWidth - textWidth)/2; + textYOffset = imageHeight/2 + 2; + imageXOffset = (fullWidth - imageWidth)/2; + imageYOffset = -textHeight/2; + break; + case COMPOUND_BOTTOM: + textXOffset = (fullWidth - textWidth)/2; + textYOffset = -imageHeight/2; + imageXOffset = (fullWidth - imageWidth)/2; + imageYOffset = textHeight/2 + 2; + break; + case COMPOUND_LEFT: + /* + * The standard image position on Windows is in the indicator + * space to the left of the entries, unless this entry is a + * radio|check button because then the indicator space will be + * used. + */ + + textXOffset = imageWidth + 2; + textYOffset = 0; + imageXOffset = 0; + imageYOffset = 0; + if ((mePtr->type != CHECK_BUTTON_ENTRY) + && (mePtr->type != RADIO_BUTTON_ENTRY)) { + textXOffset -= indicatorSpace; + if (textXOffset < 0) { + textXOffset = 0; } - break; - } - case COMPOUND_RIGHT: { - textXOffset = 0; - textYOffset = 0; - imageXOffset = textWidth + 2; - imageYOffset = 0; - break; - } - case COMPOUND_CENTER: { - textXOffset = (fullWidth - textWidth)/2; - textYOffset = 0; - imageXOffset = (fullWidth - imageWidth)/2; - imageYOffset = 0; - break; + imageXOffset = -indicatorSpace; } - case COMPOUND_NONE: {break;} + break; + case COMPOUND_RIGHT: + textXOffset = 0; + textYOffset = 0; + imageXOffset = textWidth + 2; + imageYOffset = 0; + break; + case COMPOUND_CENTER: + textXOffset = (fullWidth - textWidth)/2; + textYOffset = 0; + imageXOffset = (fullWidth - imageWidth)/2; + imageYOffset = 0; + break; + case COMPOUND_NONE: + break; } } else { textXOffset = 0; @@ -2242,7 +2206,7 @@ DrawMenuEntryLabel( imageXOffset = 0; imageYOffset = 0; } - + /* * Draw label and/or bitmap or image for entry. */ @@ -2252,42 +2216,45 @@ DrawMenuEntryLabel( && (mePtr->entryFlags & ENTRY_SELECTED)) { Tk_RedrawImage(mePtr->selectImage, 0, 0, imageWidth, imageHeight, d, leftEdge + imageXOffset, - (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset)); + (int) (y + (mePtr->height-imageHeight)/2 + imageYOffset)); } else { Tk_RedrawImage(mePtr->image, 0, 0, imageWidth, imageHeight, d, leftEdge + imageXOffset, - (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset)); + (int) (y + (mePtr->height-imageHeight)/2 + imageYOffset)); } } else if (mePtr->bitmapPtr != NULL) { Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); - XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, - (unsigned) imageWidth, (unsigned) imageHeight, + XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, + (unsigned) imageWidth, (unsigned) imageHeight, leftEdge + imageXOffset, (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset), 1); } if ((mePtr->compound != COMPOUND_NONE) || !haveImage) { if (mePtr->labelLength > 0) { int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; - char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + char *label = Tcl_GetString(mePtr->labelPtr); + if (TkWinGetPlatformTheme() == TK_THEME_WIN_CLASSIC) { - /* Win 95/98 systems draw disabled menu text with a - * 3D highlight, unless the menu item is highlighted */ - if ((mePtr->state == ENTRY_DISABLED) && - ((mePtr->entryFlags & ENTRY_PLATFORM_FLAG1) == 0)) { - COLORREF oldFgColor = gc->foreground; + /* + * Win 95/98 systems draw disabled menu text with a 3D + * highlight, unless the menu item is highlighted, + */ + + if ((mePtr->state == ENTRY_DISABLED) && + ((mePtr->entryFlags & ENTRY_PLATFORM_FLAG1) == 0)) { + COLORREF oldFgColor = gc->foreground; gc->foreground = GetSysColor(COLOR_3DHILIGHT); - Tk_DrawChars(menuPtr->display, d, gc, tkfont, label, - mePtr->labelLength, leftEdge + textXOffset + 1, - baseline + textYOffset + 1); + Tk_DrawChars(menuPtr->display, d, gc, tkfont, label, + mePtr->labelLength, leftEdge + textXOffset + 1, + baseline + textYOffset + 1); gc->foreground = oldFgColor; - } + } } - Tk_DrawChars(menuPtr->display, d, gc, tkfont, label, - mePtr->labelLength, leftEdge + textXOffset, + Tk_DrawChars(menuPtr->display, d, gc, tkfont, label, + mePtr->labelLength, leftEdge + textXOffset, baseline + textYOffset); - DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, - x + textXOffset, y + textYOffset, - width, height); + DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, + x + textXOffset, y + textYOffset, width, height); } } @@ -2295,7 +2262,7 @@ DrawMenuEntryLabel( if (menuPtr->disabledFgPtr == NULL) { XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, (unsigned) width, (unsigned) height); - } else if ((mePtr->image != NULL) + } else if ((mePtr->image != NULL) && (menuPtr->disabledImageGC != None)) { XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC, leftEdge + imageXOffset, @@ -2310,16 +2277,15 @@ DrawMenuEntryLabel( * * TkpComputeMenubarGeometry -- * - * This procedure is invoked to recompute the size and - * layout of a menu that is a menubar clone. + * This function is invoked to recompute the size and layout of a menu + * that is a menubar clone. * * Results: * None. * * Side effects: - * Fields of menu entries are changed to reflect their - * current positions, and the size of the menu window - * itself may be changed. + * Fields of menu entries are changed to reflect their current positions, + * and the size of the menu window itself may be changed. * *-------------------------------------------------------------- */ @@ -2336,26 +2302,25 @@ TkpComputeMenubarGeometry(menuPtr) * * DrawTearoffEntry -- * - * This procedure draws the background part of a menu. + * This function draws the background part of a menu. * * Results: * None. * * Side effects: - * Commands are output to X to display the menu in its - * current mode. + * Commands are output to X to display the menu in its current mode. * *---------------------------------------------------------------------- */ void DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) - TkMenu *menuPtr; /* The menu we are drawing */ - TkMenuEntry *mePtr; /* The entry we are drawing */ - Drawable d; /* The drawable we are drawing into */ - GC gc; /* The gc we are drawing with */ - Tk_Font tkfont; /* The font we are drawing with */ - CONST Tk_FontMetrics *fmPtr; /* The metrics we are drawing with */ + TkMenu *menuPtr; /* The menu we are drawing */ + TkMenuEntry *mePtr; /* The entry we are drawing */ + Drawable d; /* The drawable we are drawing into */ + GC gc; /* The gc we are drawing with */ + Tk_Font tkfont; /* The font we are drawing with */ + CONST Tk_FontMetrics *fmPtr;/* The metrics we are drawing with */ int x; int y; int width; @@ -2368,12 +2333,12 @@ DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) if (menuPtr->menuType != MASTER_MENU) { return; } - + points[0].x = x; points[0].y = y + height/2; points[1].y = points[0].y; segmentWidth = 6; - maxX = width - 1; + maxX = width - 1; border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); while (points[0].x < maxX) { @@ -2395,21 +2360,20 @@ DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) * Processes configurations for menu entries. * * Results: - * Returns standard TCL result. If TCL_ERROR is returned, then - * the interp's result contains an error message. + * Returns standard TCL result. If TCL_ERROR is returned, then the + * interp's result contains an error message. * * Side effects: - * Configuration information get set for mePtr; old resources - * get freed, if any need it. + * Configuration information get set for mePtr; old resources get freed, + * if any need it. * *---------------------------------------------------------------------- */ int TkpConfigureMenuEntry(mePtr) - register TkMenuEntry *mePtr; /* Information about menu entry; may - * or may not already have values for - * some fields. */ + register TkMenuEntry *mePtr;/* Information about menu entry; may or may + * not already have values for some fields. */ { TkMenu *menuPtr = mePtr->menuPtr; @@ -2425,8 +2389,8 @@ TkpConfigureMenuEntry(mePtr) * * TkpDrawMenuEntry -- * - * Draws the given menu entry at the given coordinates with the - * given attributes. + * Draws the given menu entry at the given coordinates with the given + * attributes. * * Results: * None. @@ -2438,21 +2402,21 @@ TkpConfigureMenuEntry(mePtr) */ void -TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, +TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, strictMotif, drawArrow) - TkMenuEntry *mePtr; /* The entry to draw */ - Drawable d; /* What to draw into */ - Tk_Font tkfont; /* Precalculated font for menu */ + TkMenuEntry *mePtr; /* The entry to draw */ + Drawable d; /* What to draw into */ + Tk_Font tkfont; /* Precalculated font for menu */ CONST Tk_FontMetrics *menuMetricsPtr; - /* Precalculated metrics for menu */ - int x; /* X-coordinate of topleft of entry */ - int y; /* Y-coordinate of topleft of entry */ - int width; /* Width of the entry rectangle */ - int height; /* Height of the current rectangle */ - int strictMotif; /* Boolean flag */ - int drawArrow; /* Whether or not to draw the cascade - * arrow for cascade items. Only applies - * to Windows. */ + /* Precalculated metrics for menu */ + int x; /* X-coordinate of topleft of entry */ + int y; /* Y-coordinate of topleft of entry */ + int width; /* Width of the entry rectangle */ + int height; /* Height of the current rectangle */ + int strictMotif; /* Boolean flag */ + int drawArrow; /* Whether or not to draw the cascade arrow + * for cascade items. Only applies to + * Windows. */ { GC gc, indicatorGC; TkMenu *menuPtr = mePtr->menuPtr; @@ -2476,11 +2440,11 @@ TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, TkMenuEntry *cascadeEntryPtr; int parentDisabled = 0; char *name; - + for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; cascadeEntryPtr != NULL; cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { - name = Tcl_GetStringFromObj(cascadeEntryPtr->namePtr, NULL); + name = Tcl_GetString(cascadeEntryPtr->namePtr); if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) { if (mePtr->state == ENTRY_DISABLED) { parentDisabled = 1; @@ -2527,16 +2491,16 @@ TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, } /* - * Need to draw the entire background, including padding. On Unix, - * for menubars, we have to draw the rest of the entry taking - * into account the padding. + * Need to draw the entire background, including padding. On Unix, for + * menubars, we have to draw the rest of the entry taking into account the + * padding. */ - - DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, + + DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y, width, height); - + if (mePtr->type == SEPARATOR_ENTRY) { - DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, + DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, width, adjustedHeight); } else if (mePtr->type == TEAROFF_ENTRY) { DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, @@ -2574,17 +2538,16 @@ TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, static void GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr) - TkMenuEntry *mePtr; /* The entry we are computing */ - Tk_Font tkfont; /* The precalculated font */ - CONST Tk_FontMetrics *fmPtr; /* The precalculated metrics */ - int *widthPtr; /* The resulting width of the label - * portion */ - int *heightPtr; /* The resulting height of the label - * portion */ + TkMenuEntry *mePtr; /* The entry we are computing */ + Tk_Font tkfont; /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr;/* The precalculated metrics */ + int *widthPtr; /* The resulting width of the label portion */ + int *heightPtr; /* The resulting height of the label + * portion */ { TkMenu *menuPtr = mePtr->menuPtr; int haveImage = 0, haveText = 0; - + if (mePtr->image != NULL) { Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr); haveImage = 1; @@ -2596,54 +2559,72 @@ GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr) *heightPtr = 0; *widthPtr = 0; } - + if (haveImage && (mePtr->compound == COMPOUND_NONE)) { - /* We don't care about the text in this case */ + /* + * We don't care about the text in this case. + */ } else { - /* Either it is compound or we don't have an image */ + /* + * Either it is compound or we don't have an image, + */ + if (mePtr->labelPtr != NULL) { int textWidth; - char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); + char *label = Tcl_GetString(mePtr->labelPtr); + textWidth = Tk_TextWidth(tkfont, label, mePtr->labelLength); if ((mePtr->compound != COMPOUND_NONE) && haveImage) { switch ((enum compound) mePtr->compound) { - case COMPOUND_TOP: - case COMPOUND_BOTTOM: { - if (textWidth > *widthPtr) { - *widthPtr = textWidth; - } - /* Add text and padding */ - *heightPtr += fmPtr->linespace + 2; - break; + case COMPOUND_TOP: + case COMPOUND_BOTTOM: + if (textWidth > *widthPtr) { + *widthPtr = textWidth; } - case COMPOUND_LEFT: - case COMPOUND_RIGHT: { - if (fmPtr->linespace > *heightPtr) { - *heightPtr = fmPtr->linespace; - } - /* Add text and padding */ - *widthPtr += textWidth + 2; - break; + + /* + * Add text and padding. + */ + + *heightPtr += fmPtr->linespace + 2; + break; + case COMPOUND_LEFT: + case COMPOUND_RIGHT: + if (fmPtr->linespace > *heightPtr) { + *heightPtr = fmPtr->linespace; } - case COMPOUND_CENTER: { - if (fmPtr->linespace > *heightPtr) { - *heightPtr = fmPtr->linespace; - } - if (textWidth > *widthPtr) { - *widthPtr = textWidth; - } - break; + + /* + * Add text and padding. + */ + + *widthPtr += textWidth + 2; + break; + case COMPOUND_CENTER: + if (fmPtr->linespace > *heightPtr) { + *heightPtr = fmPtr->linespace; + } + if (textWidth > *widthPtr) { + *widthPtr = textWidth; } - case COMPOUND_NONE: {break;} + break; + case COMPOUND_NONE: + break; } - } else { - /* We don't have an image or we're not compound */ + } else { + /* + * We don't have an image or we're not compound. + */ + *heightPtr = fmPtr->linespace; *widthPtr = textWidth; } } else { - /* An empty entry still has this height */ + /* + * An empty entry still has this height. + */ + *heightPtr = fmPtr->linespace; } } @@ -2655,36 +2636,35 @@ GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr) * * DrawMenuEntryBackground -- * - * This procedure draws the background part of a menu. + * This function draws the background part of a menu. * * Results: * None. * * Side effects: - * Commands are output to X to display the menu in its - * current mode. + * Commands are output to X to display the menu in its current mode. * *---------------------------------------------------------------------- */ static void DrawMenuEntryBackground( - TkMenu *menuPtr, /* The menu we are drawing. */ - TkMenuEntry *mePtr, /* The entry we are drawing. */ - Drawable d, /* What we are drawing into */ - Tk_3DBorder activeBorder, /* Border for active items */ - Tk_3DBorder bgBorder, /* Border for the background */ - int x, /* left edge */ - int y, /* top edge */ - int width, /* width of rectangle to draw */ - int height) /* height of rectangle to draw */ + TkMenu *menuPtr, /* The menu we are drawing. */ + TkMenuEntry *mePtr, /* The entry we are drawing. */ + Drawable d, /* What we are drawing into */ + Tk_3DBorder activeBorder, /* Border for active items */ + Tk_3DBorder bgBorder, /* Border for the background */ + int x, /* left edge */ + int y, /* top edge */ + int width, /* width of rectangle to draw */ + int height) /* height of rectangle to draw */ { - if (mePtr->state == ENTRY_ACTIVE + if (mePtr->state == ENTRY_ACTIVE || (mePtr->entryFlags & ENTRY_PLATFORM_FLAG1)!=0 ) { bgBorder = activeBorder; } - Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, - x, y, width, height, 0, TK_RELIEF_FLAT); + Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height, 0, + TK_RELIEF_FLAT); } /* @@ -2692,16 +2672,15 @@ DrawMenuEntryBackground( * * TkpComputeStandardMenuGeometry -- * - * This procedure is invoked to recompute the size and - * layout of a menu that is not a menubar clone. + * This function is invoked to recompute the size and layout of a menu + * that is not a menubar clone. * * Results: * None. * * Side effects: - * Fields of menu entries are changed to reflect their - * current positions, and the size of the menu window - * itself may be changed. + * Fields of menu entries are changed to reflect their current positions, + * and the size of the menu window itself may be changed. * *-------------------------------------------------------------- */ @@ -2716,26 +2695,25 @@ TkpComputeStandardMenuGeometry( int windowWidth, windowHeight, accelSpace; int i, j, lastColumnBreak = 0; int activeBorderWidth, borderWidth; - + if (menuPtr->tkwin == NULL) { return; } - Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, + Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, menuPtr->borderWidthPtr, &borderWidth); x = y = borderWidth; indicatorSpace = labelWidth = accelWidth = 0; windowHeight = 0; /* - * On the Mac especially, getting font metrics can be quite slow, - * so we want to do it intelligently. We are going to precalculate - * them and pass them down to all of the measuring and drawing - * routines. We will measure the font metrics of the menu once. - * If an entry does not have its own font set, then we give - * the geometry/drawing routines the menu's font and metrics. - * If an entry has its own font, we will measure that font and - * give all of the geometry/drawing the entry's font and metrics. + * On the Mac especially, getting font metrics can be quite slow, so we + * want to do it intelligently. We are going to precalculate them and pass + * them down to all of the measuring and drawing routines. We will measure + * the font metrics of the menu once. If an entry does not have its own + * font set, then we give the geometry/drawing routines the menu's font + * and metrics. If an entry has its own font, we will measure that font + * and give all of the geometry/drawing the entry's font and metrics. */ menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); @@ -2778,28 +2756,27 @@ TkpComputeStandardMenuGeometry( fmPtr, &width, &height); menuPtr->entries[i]->height = height; } else if (menuPtr->entries[i]->type == TEAROFF_ENTRY) { - GetTearoffEntryGeometry(menuPtr, menuPtr->entries[i], tkfont, + GetTearoffEntryGeometry(menuPtr, menuPtr->entries[i], tkfont, fmPtr, &width, &height); menuPtr->entries[i]->height = height; + } else { - /* - * For each entry, compute the height required by that - * particular entry, plus three widths: the width of the - * label, the width to allow for an indicator to be displayed - * to the left of the label (if any), and the width of the - * accelerator to be displayed to the right of the label - * (if any). These sizes depend, of course, on the type - * of the entry. + * For each entry, compute the height required by that particular + * entry, plus three widths: the width of the label, the width to + * allow for an indicator to be displayed to the left of the label + * (if any), and the width of the accelerator to be displayed to + * the right of the label (if any). These sizes depend, of course, + * on the type of the entry. */ - + GetMenuLabelGeometry(menuPtr->entries[i], tkfont, fmPtr, &width, &height); menuPtr->entries[i]->height = height; if (width > labelWidth) { labelWidth = width; } - + GetMenuAccelGeometry(menuPtr, menuPtr->entries[i], tkfont, fmPtr, &width, &height); if (height > menuPtr->entries[i]->height) { @@ -2809,7 +2786,7 @@ TkpComputeStandardMenuGeometry( accelWidth = width; } - GetMenuIndicatorGeometry(menuPtr, menuPtr->entries[i], tkfont, + GetMenuIndicatorGeometry(menuPtr, menuPtr->entries[i], tkfont, fmPtr, &width, &height); if (height > menuPtr->entries[i]->height) { menuPtr->entries[i]->height = height; @@ -2820,7 +2797,7 @@ TkpComputeStandardMenuGeometry( menuPtr->entries[i]->height += 2 * activeBorderWidth + 1; } - menuPtr->entries[i]->y = y; + menuPtr->entries[i]->y = y; y += menuPtr->entries[i]->height; if (y > windowHeight) { windowHeight = y; @@ -2843,10 +2820,10 @@ TkpComputeStandardMenuGeometry( windowHeight += borderWidth; - + /* - * The X server doesn't like zero dimensions, so round up to at least - * 1 (a zero-sized menu should never really occur, anyway). + * The X server doesn't like zero dimensions, so round up to at least 1 (a + * zero-sized menu should never really occur, anyway). */ if (windowWidth <= 0) { @@ -2864,8 +2841,8 @@ TkpComputeStandardMenuGeometry( * * MenuSelectEvent -- * - * Generates a "MenuSelect" virtual event. This can be used to - * do context-sensitive menu help. + * Generates a "MenuSelect" virtual event. This can be used to do + * context-sensitive menu help. * * Results: * None. @@ -2883,7 +2860,7 @@ MenuSelectEvent( XVirtualEvent event; POINTS rootPoint; DWORD msgPos; - + event.type = VirtualEvent; event.serial = menuPtr->display->request; event.send_event = 0; @@ -2893,7 +2870,7 @@ MenuSelectEvent( event.root = XRootWindow(menuPtr->display, 0); event.subwindow = None; event.time = TkpGetMS(); - + msgPos = GetMessagePos(); rootPoint = MAKEPOINTS(msgPos); event.x_root = rootPoint.x; @@ -2911,8 +2888,8 @@ MenuSelectEvent( * TkpMenuNotifyToplevelCreate -- * * This routine reconfigures the menu and the clones indicated by - * menuName becuase a toplevel has been created and any system - * menus need to be created. + * menuName becuase a toplevel has been created and any system menus need + * to be created. * * Results: * None. @@ -2925,9 +2902,8 @@ MenuSelectEvent( void TkpMenuNotifyToplevelCreate( - Tcl_Interp *interp, /* The interp the menu lives in. */ - char *menuName) /* The name of the menu to - * reconfigure. */ + Tcl_Interp *interp, /* The interp the menu lives in. */ + char *menuName) /* The name of the menu to reconfigure. */ { TkMenuReferences *menuRefPtr; TkMenu *menuPtr; @@ -2937,10 +2913,10 @@ TkpMenuNotifyToplevelCreate( if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) { for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) { - if ((menuPtr->menuType == MENUBAR) + if ((menuPtr->menuType == MENUBAR) && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; - Tcl_DoWhenIdle(ReconfigureWindowsMenu, + Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); } } @@ -2953,8 +2929,8 @@ TkpMenuNotifyToplevelCreate( * * MenuExitHandler -- * - * Throws away the utility window needed for menus and unregisters - * the class. + * Throws away the utility window needed for menus and unregisters the + * class. * * Results: * None. @@ -2969,8 +2945,8 @@ static void MenuExitHandler( ClientData clientData) /* Not used */ { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); DestroyWindow(tsdPtr->menuHWND); UnregisterClass(MENU_CLASS_NAME, Tk_GetHINSTANCE()); @@ -2988,9 +2964,9 @@ MenuExitHandler( * database name. * * Results: - * Returns a Tcl_Obj * with the default value. If there is no - * Windows-specific default for this attribute, returns NULL. - * This object has a ref count of 0. + * Returns a Tcl_Obj* with the default value. If there is no + * Windows-specific default for this attribute, returns NULL. This object + * has a ref count of 0. * * Side effects: * Storage is allocated. @@ -3010,8 +2986,7 @@ TkWinGetMenuSystemDefault( (strcmp(dbName, "borderWidth") == 0)) { valuePtr = Tcl_NewIntObj(defaultBorderWidth); } else if (strcmp(dbName, "font") == 0) { - valuePtr = Tcl_NewStringObj(Tcl_DStringValue(&menuFontDString), - -1); + valuePtr = Tcl_NewStringObj(Tcl_DStringValue(&menuFontDString), -1); } return valuePtr; @@ -3036,14 +3011,14 @@ TkWinGetMenuSystemDefault( void SetDefaults( - int firstTime) /* Is this the first time this - * has been called? */ + int firstTime) /* Is this the first time this has been + * called? */ { char sizeString[TCL_INTEGER_SPACE]; char faceName[LF_FACESIZE]; HDC scratchDC; Tcl_DString boldItalicDString; - int bold = 0; + int bold = 0; int italic = 0; TEXTMETRIC tm; int pointSize; @@ -3051,8 +3026,8 @@ SetDefaults( NONCLIENTMETRICS ncMetrics; /* - * Set all of the default options. The loop will terminate when we run - * out of options via a break statement. + * Set all of the default options. The loop will terminate when we run out + * of options via a break statement. */ defaultBorderWidth = GetSystemMetrics(SM_CXBORDER); @@ -3086,7 +3061,7 @@ SetDefaults( DeleteDC(scratchDC); DeleteObject(menuFont); - + Tcl_DStringAppendElement(&menuFontDString, faceName); sprintf(sizeString, "%d", pointSize); Tcl_DStringAppendElement(&menuFontDString, sizeString); @@ -3099,31 +3074,30 @@ SetDefaults( if (italic == 1) { Tcl_DStringAppendElement(&boldItalicDString, "italic"); } - Tcl_DStringAppendElement(&menuFontDString, + Tcl_DStringAppendElement(&menuFontDString, Tcl_DStringValue(&boldItalicDString)); } /* * Now we go ahead and get the dimensions of the check mark and the - * appropriate margins. Since this is fairly hairy, we do it here - * to save time when traversing large sets of menu items. + * appropriate margins. Since this is fairly hairy, we do it here to save + * time when traversing large sets of menu items. * - * The code below was given to me by Microsoft over the phone. It - * is the only way to insure menu items lining up, and is not - * documented. + * The code below was given to me by Microsoft over the phone. It is the + * only way to ensure menu items line up, and is not documented. */ if (TkWinGetPlatformId() >= VER_PLATFORM_WIN32_WINDOWS) { indicatorDimensions[0] = GetSystemMetrics(SM_CYMENUCHECK); indicatorDimensions[1] = ((GetSystemMetrics(SM_CXFIXEDFRAME) + - GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXMENUCHECK) + 7) & 0xFFF8) - GetSystemMetrics(SM_CXFIXEDFRAME); } else { DWORD dimensions = GetMenuCheckMarkDimensions(); indicatorDimensions[0] = HIWORD(dimensions); indicatorDimensions[1] = LOWORD(dimensions); - } + } } /* @@ -3146,8 +3120,8 @@ void TkpMenuInit() { WNDCLASS wndClass; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); wndClass.style = CS_OWNDC; wndClass.lpfnWndProc = TkWinMenuProc; @@ -3159,28 +3133,29 @@ TkpMenuInit() wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = MENU_CLASS_NAME; - if(!RegisterClass(&wndClass)) { - panic("Failed to register menu window class."); + if (!RegisterClass(&wndClass)) { + Tcl_Panic("Failed to register menu window class."); } tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP, - 0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL); + 0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL); - if(!tsdPtr->menuHWND) { - panic("Failed to create the menu window."); + if (!tsdPtr->menuHWND) { + Tcl_Panic("Failed to create the menu window."); } wndClass.lpfnWndProc = TkWinEmbeddedMenuProc; wndClass.lpszClassName = EMBEDDED_MENU_CLASS_NAME; - if(!RegisterClass(&wndClass)) { - panic ("Failed to register embedded menu window class."); + if (!RegisterClass(&wndClass)) { + Tcl_Panic("Failed to register embedded menu window class."); } - tsdPtr->embeddedMenuHWND = CreateWindow(EMBEDDED_MENU_CLASS_NAME, "EmbeddedMenuWindow", WS_POPUP, - 0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL); + tsdPtr->embeddedMenuHWND = + CreateWindow(EMBEDDED_MENU_CLASS_NAME, "EmbeddedMenuWindow", + WS_POPUP, 0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL); - if(!tsdPtr->embeddedMenuHWND) { - panic("Failed to create the embedded menu window."); + if (!tsdPtr->embeddedMenuHWND) { + Tcl_Panic("Failed to create the embedded menu window."); } TkCreateExitHandler(MenuExitHandler, (ClientData) NULL); @@ -3192,11 +3167,10 @@ TkpMenuInit() * * Tk_GetMenuHWND -- * - * This function returns the HWND of a hidden menu Window that - * processes messages of a popup menu. This hidden menu window - * is used to handle either a dynamic popup menu in the same - * process or a pull-down menu of an embedded window in a - * different process. + * This function returns the HWND of a hidden menu Window that processes + * messages of a popup menu. This hidden menu window is used to handle + * either a dynamic popup menu in the same process or a pull-down menu of + * an embedded window in a different process. * * Results: * Returns the HWND of the hidden menu Window. @@ -3211,8 +3185,8 @@ HWND Tk_GetMenuHWND(tkwin) Tk_Window tkwin; { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); TkMenuInit(); return tsdPtr->embeddedMenuHWND; } @@ -3236,9 +3210,17 @@ Tk_GetMenuHWND(tkwin) void TkpMenuThreadInit() { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); Tcl_InitHashTable(&tsdPtr->winMenuTable, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&tsdPtr->commandTable, TCL_ONE_WORD_KEYS); } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |