Logo Search packages:      
Sourcecode: tcltk8.0-ja version File versions  Download package

tkWinDialog.c

/*
 * 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.
 *
 * RCS: @(#) $Id: tkWinDialog.c,v 1.2 1998/09/14 18:23:59 stanton Exp $
 *
 */
 
#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;
}

Generated by  Doxygen 1.6.0   Back to index