diff options
Diffstat (limited to 'win/tkWinDialog.c')
-rw-r--r-- | win/tkWinDialog.c | 1050 |
1 files changed, 1050 insertions, 0 deletions
diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c new file mode 100644 index 0000000..7d01edb --- /dev/null +++ b/win/tkWinDialog.c @@ -0,0 +1,1050 @@ +/* + * tkWinDialog.c -- + * + * Contains the Windows implementation of the common dialog boxes. + * + * 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. + * + * SCCS: @(#) tkWinDialog.c 1.10 97/10/21 11:29:18 + * + */ + +#include "tkWinInt.h" +#include "tkFileFilter.h" + +#include <commdlg.h> /* includes common dialog functionality */ +#include <dlgs.h> /* includes common dialog template defines */ +#include <cderr.h> /* includes the common dialog error codes */ + +#if ((TK_MAJOR_VERSION == 4) && (TK_MINOR_VERSION <= 2)) +/* + * The following function is implemented on tk4.3 and after only + */ +#define Tk_GetHWND TkWinGetHWND +#endif + +#define SAVE_FILE 0 +#define OPEN_FILE 1 + +/*---------------------------------------------------------------------- + * MsgTypeInfo -- + * + * This structure stores the type of available message box in an + * easy-to-process format. Used by th Tk_MessageBox() function + *---------------------------------------------------------------------- + */ +typedef struct MsgTypeInfo { + char * name; + int type; + int numButtons; + char * btnNames[3]; +} MsgTypeInfo; + +#define NUM_TYPES 6 + +static MsgTypeInfo +msgTypeInfo[NUM_TYPES] = { + {"abortretryignore", MB_ABORTRETRYIGNORE, 3, {"abort", "retry", "ignore"}}, + {"ok", MB_OK, 1, {"ok" }}, + {"okcancel", MB_OKCANCEL, 2, {"ok", "cancel" }}, + {"retrycancel", MB_RETRYCANCEL, 2, {"retry", "cancel" }}, + {"yesno", MB_YESNO, 2, {"yes", "no" }}, + {"yesnocancel", MB_YESNOCANCEL, 3, {"yes", "no", "cancel"}} +}; + +/* + * The following structure is used in the GetOpenFileName() and + * GetSaveFileName() calls. + */ +typedef struct _OpenFileData { + Tcl_Interp * interp; + TCHAR szFile[MAX_PATH+1]; +} OpenFileData; + +/* + * The following structure is used in the ChooseColor() call. + */ +typedef struct _ChooseColorData { + Tcl_Interp * interp; + char * title; /* Title of the color dialog */ +} ChooseColorData; + + +static int GetFileName _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv, + int isOpen)); +static UINT CALLBACK ColorDlgHookProc _ANSI_ARGS_((HWND hDlg, UINT uMsg, + WPARAM wParam, LPARAM lParam)); +static int MakeFilter _ANSI_ARGS_((Tcl_Interp *interp, + OPENFILENAME *ofnPtr, char * string)); +static int ParseFileDlgArgs _ANSI_ARGS_((Tcl_Interp * interp, + OPENFILENAME *ofnPtr, int argc, char ** argv, + int isOpen)); +static int ProcessCDError _ANSI_ARGS_((Tcl_Interp * interp, + DWORD dwErrorCode, HWND hWnd)); + +/* + *---------------------------------------------------------------------- + * + * EvalArgv -- + * + * Invokes the Tcl procedure with the arguments. argv[0] is set by + * the caller of this function. It may be different than cmdName. + * The TCL command will see argv[0], not cmdName, as its name if it + * invokes [lindex [info level 0] 0] + * + * Results: + * TCL_ERROR if the command does not exist and cannot be autoloaded. + * Otherwise, return the result of the evaluation of the command. + * + * Side effects: + * The command may be autoloaded. + * + *---------------------------------------------------------------------- + */ + +static int +EvalArgv(interp, cmdName, argc, argv) + Tcl_Interp *interp; /* Current interpreter. */ + char * cmdName; /* Name of the TCL command to call */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + Tcl_CmdInfo cmdInfo; + + if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) { + char * cmdArgv[2]; + + /* + * This comand is not in the interpreter yet -- looks like we + * have to auto-load it + */ + if (!Tcl_GetCommandInfo(interp, "auto_load", &cmdInfo)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "cannot execute command \"auto_load\"", + NULL); + return TCL_ERROR; + } + + cmdArgv[0] = "auto_load"; + cmdArgv[1] = cmdName; + + if ((*cmdInfo.proc)(cmdInfo.clientData, interp, 2, cmdArgv)!= TCL_OK){ + return TCL_ERROR; + } + + if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "cannot auto-load command \"", + cmdName, "\"",NULL); + return TCL_ERROR; + } + } + + return (*cmdInfo.proc)(cmdInfo.clientData, interp, argc, argv); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_ChooseColorCmd -- + * + * This procedure 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. + * This window is not destroyed and will be reused the next time the + * application invokes the "tk_chooseColor" command. + * + *---------------------------------------------------------------------- + */ + +int +Tk_ChooseColorCmd(clientData, interp, argc, argv) + ClientData clientData; /* Main window associated with interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + Tk_Window parent = Tk_MainWindow(interp); + ChooseColorData custData; + int oldMode; + CHOOSECOLOR chooseColor; + char * colorStr = NULL; + int i; + int winCode, tclCode; + XColor * colorPtr = NULL; + static inited = 0; + static long dwCustColors[16]; + static long oldColor; /* the color selected last time */ + + custData.title = NULL; + + if (!inited) { + /* + * dwCustColors stores the custom color which the user can + * modify. We store these colors in a fixed 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)) ; + } + oldColor = RGB(0xa0,0xa0,0xa0); + inited = 1; + } + + /* + * 1. Parse the arguments + */ + + chooseColor.lStructSize = sizeof(CHOOSECOLOR) ; + chooseColor.hwndOwner = 0; /* filled in below */ + chooseColor.hInstance = 0; + chooseColor.rgbResult = oldColor; + chooseColor.lpCustColors = (LPDWORD) dwCustColors ; + chooseColor.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK; + chooseColor.lCustData = (LPARAM)&custData; + chooseColor.lpfnHook = ColorDlgHookProc; + chooseColor.lpTemplateName = NULL; + + for (i=1; i<argc; i+=2) { + int v = i+1; + int len = strlen(argv[i]); + + if (strncmp(argv[i], "-initialcolor", len)==0) { + if (v==argc) {goto arg_missing;} + + colorStr = argv[v]; + } + else if (strncmp(argv[i], "-parent", len)==0) { + if (v==argc) {goto arg_missing;} + + parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); + if (parent == NULL) { + return TCL_ERROR; + } + } + else if (strncmp(argv[i], "-title", len)==0) { + if (v==argc) {goto arg_missing;} + + custData.title = argv[v]; + } + else { + Tcl_AppendResult(interp, "unknown option \"", + argv[i], "\", must be -initialcolor, -parent or -title", + NULL); + return TCL_ERROR; + } + } + + if (Tk_WindowId(parent) == None) { + Tk_MakeWindowExist(parent); + } + chooseColor.hwndOwner = Tk_GetHWND(Tk_WindowId(parent)); + + if (colorStr != NULL) { + colorPtr = Tk_GetColor(interp, Tk_MainWindow(interp), colorStr); + if (!colorPtr) { + return TCL_ERROR; + } + chooseColor.rgbResult = RGB((colorPtr->red/0x100), + (colorPtr->green/0x100), (colorPtr->blue/0x100)); + } + + /* + * 2. Popup the dialog + */ + + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + winCode = ChooseColor(&chooseColor); + (void) Tcl_SetServiceMode(oldMode); + + /* + * Clear the interp result since anything may have happened during the + * modal loop. + */ + + Tcl_ResetResult(interp); + + /* + * 3. Process the result of the dialog + */ + if (winCode) { + /* + * User has selected a color + */ + char result[100]; + + sprintf(result, "#%02x%02x%02x", + GetRValue(chooseColor.rgbResult), + GetGValue(chooseColor.rgbResult), + GetBValue(chooseColor.rgbResult)); + Tcl_AppendResult(interp, result, NULL); + tclCode = TCL_OK; + + oldColor = chooseColor.rgbResult; + } else { + /* + * User probably pressed Cancel, or an error occurred + */ + tclCode = ProcessCDError(interp, CommDlgExtendedError(), + chooseColor.hwndOwner); + } + + if (colorPtr) { + Tk_FreeColor(colorPtr); + } + + return tclCode; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", + NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * ColorDlgHookProc -- + * + * Gets called during the execution of the color dialog. It processes + * the "interesting" messages that Windows send to the dialog. + * + * Results: + * TRUE if the message has been processed, FALSE otherwise. + * + * Side effects: + * Changes the title of the dialog window when it is popped up. + * + *---------------------------------------------------------------------- + */ + +static UINT +CALLBACK ColorDlgHookProc(hDlg, uMsg, wParam, lParam) + HWND hDlg; /* Handle to the color dialog */ + UINT uMsg; /* Type of message */ + WPARAM wParam; /* word param, interpretation depends on uMsg*/ + LPARAM lParam; /* long param, interpretation depends on uMsg*/ +{ + CHOOSECOLOR * ccPtr; + ChooseColorData * pCustData; + + switch (uMsg) { + case WM_INITDIALOG: + /* Save the pointer to CHOOSECOLOR so that we can use it later */ + SetWindowLong(hDlg, DWL_USER, lParam); + + /* Set the title string of the dialog */ + ccPtr = (CHOOSECOLOR*)lParam; + pCustData = (ChooseColorData*)(ccPtr->lCustData); + if (pCustData->title && *(pCustData->title)) { + SetWindowText(hDlg, (LPCSTR)pCustData->title); + } + + return TRUE; + } + + return FALSE; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetOpenFileCmd -- + * + * This procedure 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. + * This window is not destroyed and will be reused the next time + * the application invokes the "tk_getOpenFile" or + * "tk_getSaveFile" command. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetOpenFileCmd(clientData, interp, argc, argv) + ClientData clientData; /* Main window associated with interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + return GetFileName(clientData, interp, argc, argv, OPEN_FILE); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetSaveFileCmd -- + * + * Same as Tk_GetOpenFileCmd but opens a "save file" dialog box + * instead + * + * Results: + * Same as Tk_GetOpenFileCmd. + * + * Side effects: + * Same as Tk_GetOpenFileCmd. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetSaveFileCmd(clientData, interp, argc, argv) + ClientData clientData; /* Main window associated with interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + return GetFileName(clientData, interp, argc, argv, SAVE_FILE); +} + +/* + *---------------------------------------------------------------------- + * + * GetFileName -- + * + * Calls GetOpenFileName() or GetSaveFileName(). + * + * Results: + * See user documentation. + * + * Side effects: + * See user documentation. + * + *---------------------------------------------------------------------- + */ + +static int +GetFileName(clientData, interp, argc, argv, isOpen) + ClientData clientData; /* Main window associated with interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ + int isOpen; /* true if we should call GetOpenFileName(), + * false if we should call GetSaveFileName() */ +{ + OPENFILENAME openFileName, *ofnPtr; + int tclCode, winCode, oldMode; + OpenFileData *custData; + char buffer[MAX_PATH+1]; + + ofnPtr = &openFileName; + + /* + * 1. Parse the arguments. + */ + if (ParseFileDlgArgs(interp, ofnPtr, argc, argv, isOpen) != TCL_OK) { + return TCL_ERROR; + } + custData = (OpenFileData*) ofnPtr->lCustData; + + /* + * 2. Call the common dialog function. + */ + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + GetCurrentDirectory(MAX_PATH+1, buffer); + if (isOpen) { + winCode = GetOpenFileName(ofnPtr); + } else { + winCode = GetSaveFileName(ofnPtr); + } + SetCurrentDirectory(buffer); + (void) Tcl_SetServiceMode(oldMode); + + /* + * Clear the interp result since anything may have happened during the + * modal loop. + */ + + Tcl_ResetResult(interp); + + if (ofnPtr->lpstrInitialDir != NULL) { + ckfree((char*) ofnPtr->lpstrInitialDir); + } + + /* + * 3. Process the results. + */ + if (winCode) { + char *p; + Tcl_ResetResult(interp); + + for (p = custData->szFile; p && *p; p++) { + /* + * Change the pathname to the Tcl "normalized" pathname, where + * back slashes are used instead of forward slashes + */ + if (*p == '\\') { + *p = '/'; + } + } + Tcl_AppendResult(interp, custData->szFile, NULL); + tclCode = TCL_OK; + } else { + tclCode = ProcessCDError(interp, CommDlgExtendedError(), + ofnPtr->hwndOwner); + } + + if (custData) { + ckfree((char*)custData); + } + if (ofnPtr->lpstrFilter) { + ckfree((char*)ofnPtr->lpstrFilter); + } + + return tclCode; +} + +/* + *---------------------------------------------------------------------- + * + * ParseFileDlgArgs -- + * + * Parses the arguments passed to tk_getOpenFile and tk_getSaveFile. + * + * Results: + * A standard TCL return value. + * + * Side effects: + * The OPENFILENAME structure is initialized and modified according + * to the arguments. + * + *---------------------------------------------------------------------- + */ + +static int +ParseFileDlgArgs(interp, ofnPtr, argc, argv, isOpen) + Tcl_Interp * interp; /* Current interpreter. */ + OPENFILENAME *ofnPtr; /* Info about the file dialog */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ + int isOpen; /* true if we should call GetOpenFileName(), + * false if we should call GetSaveFileName() */ +{ + OpenFileData * custData; + int i; + Tk_Window parent = Tk_MainWindow(interp); + int doneFilter = 0; + int windowsMajorVersion; + Tcl_DString buffer; + + custData = (OpenFileData*)ckalloc(sizeof(OpenFileData)); + custData->interp = interp; + strcpy(custData->szFile, ""); + + /* Fill in the OPENFILENAME structure to */ + ofnPtr->lStructSize = sizeof(OPENFILENAME); + ofnPtr->hwndOwner = 0; /* filled in below */ + ofnPtr->lpstrFilter = NULL; + ofnPtr->lpstrCustomFilter = NULL; + ofnPtr->nMaxCustFilter = 0; + ofnPtr->nFilterIndex = 0; + ofnPtr->lpstrFile = custData->szFile; + ofnPtr->nMaxFile = sizeof(custData->szFile); + ofnPtr->lpstrFileTitle = NULL; + ofnPtr->nMaxFileTitle = 0; + ofnPtr->lpstrInitialDir = NULL; + ofnPtr->lpstrTitle = NULL; + ofnPtr->nFileOffset = 0; + ofnPtr->nFileExtension = 0; + ofnPtr->lpstrDefExt = NULL; + ofnPtr->lpfnHook = NULL; + ofnPtr->lCustData = (DWORD)custData; + ofnPtr->lpTemplateName = NULL; + ofnPtr->Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + + windowsMajorVersion = LOBYTE(LOWORD(GetVersion())); + if (windowsMajorVersion >= 4) { + /* + * Use the "explorer" style file selection box on platforms that + * support it (Win95 and NT4.0, both have a major version number + * of 4) + */ + ofnPtr->Flags |= OFN_EXPLORER; + } + + + if (isOpen) { + ofnPtr->Flags |= OFN_FILEMUSTEXIST; + } else { + ofnPtr->Flags |= OFN_OVERWRITEPROMPT; + } + + for (i=1; i<argc; i+=2) { + int v = i+1; + int len = strlen(argv[i]); + + if (strncmp(argv[i], "-defaultextension", len)==0) { + if (v==argc) {goto arg_missing;} + + ofnPtr->lpstrDefExt = argv[v]; + if (ofnPtr->lpstrDefExt[0] == '.') { + /* Windows will insert the dot for us */ + ofnPtr->lpstrDefExt ++; + } + } + else if (strncmp(argv[i], "-filetypes", len)==0) { + if (v==argc) {goto arg_missing;} + + if (MakeFilter(interp, ofnPtr, argv[v]) != TCL_OK) { + return TCL_ERROR; + } + doneFilter = 1; + } + else if (strncmp(argv[i], "-initialdir", len)==0) { + if (v==argc) {goto arg_missing;} + + if (Tcl_TranslateFileName(interp, argv[v], &buffer) == NULL) { + return TCL_ERROR; + } + ofnPtr->lpstrInitialDir = ckalloc(Tcl_DStringLength(&buffer)+1); + strcpy((char*)ofnPtr->lpstrInitialDir, Tcl_DStringValue(&buffer)); + Tcl_DStringFree(&buffer); + } + else if (strncmp(argv[i], "-initialfile", len)==0) { + if (v==argc) {goto arg_missing;} + + if (Tcl_TranslateFileName(interp, argv[v], &buffer) == NULL) { + return TCL_ERROR; + } + strcpy(ofnPtr->lpstrFile, Tcl_DStringValue(&buffer)); + Tcl_DStringFree(&buffer); + } + else if (strncmp(argv[i], "-parent", len)==0) { + if (v==argc) {goto arg_missing;} + + parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); + if (parent == NULL) { + return TCL_ERROR; + } + } + else if (strncmp(argv[i], "-title", len)==0) { + if (v==argc) {goto arg_missing;} + + ofnPtr->lpstrTitle = argv[v]; + } + else { + Tcl_AppendResult(interp, "unknown option \"", + argv[i], "\", must be -defaultextension, ", + "-filetypes, -initialdir, -initialfile, -parent or -title", + NULL); + return TCL_ERROR; + } + } + + if (!doneFilter) { + if (MakeFilter(interp, ofnPtr, "") != TCL_OK) { + return TCL_ERROR; + } + } + + if (Tk_WindowId(parent) == None) { + Tk_MakeWindowExist(parent); + } + ofnPtr->hwndOwner = Tk_GetHWND(Tk_WindowId(parent)); + + return TCL_OK; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", + NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * MakeFilter -- + * + * Allocate a buffer to store the filters in a format understood by + * Windows + * + * Results: + * A standard TCL return value. + * + * Side effects: + * ofnPtr->lpstrFilter is modified. + * + *---------------------------------------------------------------------- + */ +static int MakeFilter(interp, ofnPtr, string) + Tcl_Interp *interp; /* Current interpreter. */ + OPENFILENAME *ofnPtr; /* Info about the file dialog */ + char *string; /* String value of the -filetypes option */ +{ + char *filterStr; + char *p; + int pass; + FileFilterList flist; + FileFilter *filterPtr; + + TkInitFileFilters(&flist); + if (TkGetFileFilters(interp, &flist, string, 1) != TCL_OK) { + return TCL_ERROR; + } + + if (flist.filters == NULL) { + /* + * Use "All Files (*.*) as the default filter is none is specified + */ + char *defaultFilter = "All Files (*.*)"; + + p = filterStr = (char*)ckalloc(30 * sizeof(char)); + + strcpy(p, defaultFilter); + p+= strlen(defaultFilter); + + *p++ = '\0'; + *p++ = '*'; + *p++ = '.'; + *p++ = '*'; + *p++ = '\0'; + *p++ = '\0'; + *p = '\0'; + + } else { + /* 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. + */ + + /* + * 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(strlen(string) * 3); + + for (filterPtr = flist.filters, p = filterStr; filterPtr; + filterPtr = filterPtr->next) { + char *sep; + FileFilterClause *clausePtr; + + /* + * First, put in the name of the file type + */ + strcpy(p, filterPtr->name); + p+= strlen(filterPtr->name); + *p++ = ' '; + *p++ = '('; + + 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 + */ + sep = ""; + for (clausePtr=filterPtr->clauses;clausePtr; + clausePtr=clausePtr->next) { + GlobPattern *globPtr; + + + for (globPtr=clausePtr->patterns; globPtr; + globPtr=globPtr->next) { + strcpy(p, sep); + p+= strlen(sep); + strcpy(p, globPtr->pattern); + p+= strlen(globPtr->pattern); + + if (pass==1) { + sep = ","; + } else { + sep = ";"; + } + } + } + if (pass == 1) { + if (pass == 1) { + *p ++ = ')'; + } + } + *p ++ = '\0'; + } + } + + /* + * Windows requires the filter string to be ended by two NULL + * characters. + */ + *p++ = '\0'; + *p = '\0'; + } + + if (ofnPtr->lpstrFilter != NULL) { + ckfree((char*)ofnPtr->lpstrFilter); + } + ofnPtr->lpstrFilter = filterStr; + + TkFreeFileFilters(&flist); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_MessageBoxCmd -- + * + * This procedure 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 + * returns. + * + *---------------------------------------------------------------------- + */ + +int +Tk_MessageBoxCmd(clientData, interp, argc, argv) + ClientData clientData; /* Main window associated with interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + int flags; + Tk_Window parent = Tk_MainWindow(interp); + HWND hWnd; + char *message = ""; + char *title = ""; + int icon = MB_ICONINFORMATION; + int type = MB_OK; + int i, j; + char *result; + int code, oldMode; + char *defaultBtn = NULL; + int defaultBtnIdx = -1; + + for (i=1; i<argc; i+=2) { + int v = i+1; + int len = strlen(argv[i]); + + if (strncmp(argv[i], "-default", len)==0) { + if (v==argc) {goto arg_missing;} + + defaultBtn = argv[v]; + } + else if (strncmp(argv[i], "-icon", len)==0) { + if (v==argc) {goto arg_missing;} + + if (strcmp(argv[v], "error") == 0) { + icon = MB_ICONERROR; + } + else if (strcmp(argv[v], "info") == 0) { + icon = MB_ICONINFORMATION; + } + else if (strcmp(argv[v], "question") == 0) { + icon = MB_ICONQUESTION; + } + else if (strcmp(argv[v], "warning") == 0) { + icon = MB_ICONWARNING; + } + else { + Tcl_AppendResult(interp, "invalid icon \"", argv[v], + "\", must be error, info, question or warning", NULL); + return TCL_ERROR; + } + } + else if (strncmp(argv[i], "-message", len)==0) { + if (v==argc) {goto arg_missing;} + + message = argv[v]; + } + else if (strncmp(argv[i], "-parent", len)==0) { + if (v==argc) {goto arg_missing;} + + parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); + if (parent == NULL) { + return TCL_ERROR; + } + } + else if (strncmp(argv[i], "-title", len)==0) { + if (v==argc) {goto arg_missing;} + + title = argv[v]; + } + else if (strncmp(argv[i], "-type", len)==0) { + int found = 0; + + if (v==argc) {goto arg_missing;} + + for (j=0; j<NUM_TYPES; j++) { + if (strcmp(argv[v], msgTypeInfo[j].name) == 0) { + type = msgTypeInfo[j].type; + found = 1; + break; + } + } + if (!found) { + Tcl_AppendResult(interp, "invalid message box type \"", + argv[v], "\", must be abortretryignore, ok, ", + "okcancel, retrycancel, yesno or yesnocancel", NULL); + return TCL_ERROR; + } + } + else { + Tcl_AppendResult(interp, "unknown option \"", + argv[i], "\", must be -default, -icon, ", + "-message, -parent, -title or -type", NULL); + return TCL_ERROR; + } + } + + /* Make sure we have a valid hWnd to act as the parent of this message box + */ + if (Tk_WindowId(parent) == None) { + Tk_MakeWindowExist(parent); + } + hWnd = Tk_GetHWND(Tk_WindowId(parent)); + + if (defaultBtn != NULL) { + for (i=0; i<NUM_TYPES; i++) { + if (type == msgTypeInfo[i].type) { + for (j=0; j<msgTypeInfo[i].numButtons; j++) { + if (strcmp(defaultBtn, msgTypeInfo[i].btnNames[j])==0) { + defaultBtnIdx = j; + break; + } + } + if (defaultBtnIdx < 0) { + Tcl_AppendResult(interp, "invalid default button \"", + defaultBtn, "\"", NULL); + return TCL_ERROR; + } + break; + } + } + + switch (defaultBtnIdx) { + case 0: flags = MB_DEFBUTTON1; break; + case 1: flags = MB_DEFBUTTON2; break; + case 2: flags = MB_DEFBUTTON3; break; + case 3: flags = MB_DEFBUTTON4; break; + } + } else { + flags = 0; + } + + flags |= icon | type; + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + code = MessageBox(hWnd, message, title, flags|MB_SYSTEMMODAL); + (void) Tcl_SetServiceMode(oldMode); + + switch (code) { + case IDABORT: result = "abort"; break; + case IDCANCEL: result = "cancel"; break; + case IDIGNORE: result = "ignore"; break; + case IDNO: result = "no"; break; + case IDOK: result = "ok"; break; + case IDRETRY: result = "retry"; break; + case IDYES: result = "yes"; break; + default: result = ""; + } + + /* + * When we come to here interp->result may have been changed by some + * background scripts. Call Tcl_SetResult() to make sure that any stuff + * lingering in interp->result will not appear in the result of + * this command. + */ + + Tcl_SetResult(interp, result, TCL_STATIC); + return TCL_OK; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", + NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * ProcessCDError -- + * + * This procedure gets called if a Windows-specific error message + * has occurred during the execution of a common dialog or the + * user has pressed the CANCEL button. + * + * Results: + * If an error has indeed happened, returns a standard TCL result + * that reports the error code in string format. If the user has + * pressed the CANCEL button (dwErrorCode == 0), resets + * interp->result to the empty string. + * + * Side effects: + * interp->result is changed. + * + *---------------------------------------------------------------------- + */ +static int ProcessCDError(interp, dwErrorCode, hWnd) + Tcl_Interp * interp; /* Current interpreter. */ + DWORD dwErrorCode; /* The Windows-specific error code */ + HWND hWnd; /* window in which the error happened*/ +{ + char *string; + + Tcl_ResetResult(interp); + + switch(dwErrorCode) { + case 0: /* User has hit CANCEL */ + return TCL_OK; + + case CDERR_DIALOGFAILURE: string="CDERR_DIALOGFAILURE"; break; + case CDERR_STRUCTSIZE: string="CDERR_STRUCTSIZE"; break; + case CDERR_INITIALIZATION: string="CDERR_INITIALIZATION"; break; + case CDERR_NOTEMPLATE: string="CDERR_NOTEMPLATE"; break; + case CDERR_NOHINSTANCE: string="CDERR_NOHINSTANCE"; break; + case CDERR_LOADSTRFAILURE: string="CDERR_LOADSTRFAILURE"; break; + case CDERR_FINDRESFAILURE: string="CDERR_FINDRESFAILURE"; break; + case CDERR_LOADRESFAILURE: string="CDERR_LOADRESFAILURE"; break; + case CDERR_LOCKRESFAILURE: string="CDERR_LOCKRESFAILURE"; break; + case CDERR_MEMALLOCFAILURE: string="CDERR_MEMALLOCFAILURE"; break; + case CDERR_MEMLOCKFAILURE: string="CDERR_MEMLOCKFAILURE"; break; + case CDERR_NOHOOK: string="CDERR_NOHOOK"; break; + case PDERR_SETUPFAILURE: string="PDERR_SETUPFAILURE"; break; + case PDERR_PARSEFAILURE: string="PDERR_PARSEFAILURE"; break; + case PDERR_RETDEFFAILURE: string="PDERR_RETDEFFAILURE"; break; + case PDERR_LOADDRVFAILURE: string="PDERR_LOADDRVFAILURE"; break; + case PDERR_GETDEVMODEFAIL: string="PDERR_GETDEVMODEFAIL"; break; + case PDERR_INITFAILURE: string="PDERR_INITFAILURE"; break; + case PDERR_NODEVICES: string="PDERR_NODEVICES"; break; + case PDERR_NODEFAULTPRN: string="PDERR_NODEFAULTPRN"; break; + case PDERR_DNDMMISMATCH: string="PDERR_DNDMMISMATCH"; break; + case PDERR_CREATEICFAILURE: string="PDERR_CREATEICFAILURE"; break; + case PDERR_PRINTERNOTFOUND: string="PDERR_PRINTERNOTFOUND"; break; + case CFERR_NOFONTS: string="CFERR_NOFONTS"; break; + case FNERR_SUBCLASSFAILURE: string="FNERR_SUBCLASSFAILURE"; break; + case FNERR_INVALIDFILENAME: string="FNERR_INVALIDFILENAME"; break; + case FNERR_BUFFERTOOSMALL: string="FNERR_BUFFERTOOSMALL"; break; + + default: + string="unknown error"; + } + + Tcl_AppendResult(interp, "Win32 internal error: ", string, NULL); + return TCL_ERROR; +} |