tkMacDialog.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:40k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacDialog.c --
  3.  *
  4.  * Contains the Mac implementation of the common dialog boxes.
  5.  *
  6.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * RCS: @(#) $Id: tkMacDialog.c,v 1.9 2002/04/08 09:04:38 das Exp $
  12.  */
  13. #include <Gestalt.h>
  14. #include <Aliases.h>
  15. #include <Errors.h>
  16. #include <Strings.h>
  17. #include <MoreFiles.h>
  18. #include <MoreFilesExtras.h>
  19. #include <StandardFile.h>
  20. #include <ColorPicker.h>
  21. #include <Lowmem.h>
  22. #include <Navigation.h>
  23. #include "tkPort.h"
  24. #include "tkInt.h"
  25. #include "tclMacInt.h"
  26. #include "tkMacInt.h"
  27. #include "tkFileFilter.h"
  28. #ifndef StrLength
  29. #define StrLength(s)  (*((unsigned char *) (s)))
  30. #endif
  31. #ifndef StrBody
  32. #define StrBody(s) ((char *) (s) + 1)
  33. #endif
  34. /*
  35.  * The following are ID's for resources that are defined in tkMacResource.r
  36.  */
  37. #define OPEN_BOX        130
  38. #define OPEN_POPUP      131
  39. #define OPEN_MENU       132
  40. #define OPEN_POPUP_ITEM 10
  41. #define SAVE_FILE 0
  42. #define OPEN_FILE 1
  43. #define CHOOSE_FOLDER   2
  44. #define MATCHED 0
  45. #define UNMATCHED 1
  46. /*
  47.  * The following structure is used in the GetFileName() function. It stored
  48.  * information about the file dialog and the file filters.
  49.  */
  50. typedef struct _OpenFileData {
  51.     FileFilterList fl; /* List of file filters. */
  52.     SInt16 curType; /* The filetype currently being
  53.  * listed. */
  54.     short popupItem; /* Item number of the popup in the
  55.  * dialog. */
  56.     int usePopup; /* True if we show the popup menu (this
  57.       * is an open operation and the
  58.  * -filetypes option is set). */
  59. } OpenFileData;
  60. static pascal Boolean FileFilterProc _ANSI_ARGS_((CInfoPBPtr pb,
  61.     void *myData));
  62. static int  GetFileName _ANSI_ARGS_ ((ClientData clientData, 
  63.     Tcl_Interp *interp, int objc, 
  64.     Tcl_Obj *CONST objv[], int isOpen));
  65. static int  NavGetFileName _ANSI_ARGS_ ((ClientData clientData, 
  66.     Tcl_Interp *interp, int objc, 
  67.     Tcl_Obj *CONST objv[], int isOpen));
  68. static Boolean MatchOneType _ANSI_ARGS_((StringPtr fileNamePtr, OSType fileType,
  69.     OpenFileData *myofdPtr, FileFilter *filterPtr));
  70. static pascal short  OpenHookProc _ANSI_ARGS_((short item,
  71.     DialogPtr theDialog, OpenFileData * myofdPtr));
  72. static int  ParseFileDlgArgs _ANSI_ARGS_ ((Tcl_Interp * interp,
  73.     OpenFileData * myofdPtr, int argc, char ** argv,
  74.     int isOpen));
  75. static pascal Boolean   OpenFileFilterProc(AEDesc* theItem, void* info, 
  76.                             NavCallBackUserData callBackUD,
  77.                             NavFilterModes filterMode );
  78. pascal void             OpenEventProc(NavEventCallbackMessage callBackSelector,
  79.                             NavCBRecPtr callBackParms,
  80.                             NavCallBackUserData callBackUD );
  81. static void             InitFileDialogs();
  82. static int              StdGetFile(Tcl_Interp *interp, OpenFileData *ofd,
  83.                             unsigned char *initialFile, int isOpen);
  84. static int              NavServicesGetFile(Tcl_Interp *interp, OpenFileData *ofd,
  85.                             AEDesc *initialDesc, unsigned char *initialFile,
  86.                             StringPtr title, StringPtr message, int multiple, int isOpen);
  87. static int              HandleInitialDirectory (Tcl_Interp *interp, char *initialDir, FSSpec *dirSpec, 
  88.                             AEDesc *dirDescPtr);                            
  89. /*
  90.  * Filter and hook functions used by the tk_getOpenFile and tk_getSaveFile
  91.  * commands.
  92.  */
  93. int fileDlgInited = 0;
  94. int useNavServices = 0;
  95. NavObjectFilterUPP openFileFilterUPP;
  96. NavEventUPP openFileEventUPP;
  97. static FileFilterYDUPP openFilter = NULL;
  98. static DlgHookYDUPP openHook = NULL;
  99. static DlgHookYDUPP saveHook = NULL;
  100.   
  101. /*
  102.  *----------------------------------------------------------------------
  103.  *
  104.  * Tk_ChooseColorObjCmd --
  105.  *
  106.  * This procedure implements the color dialog box for the Mac
  107.  * platform. See the user documentation for details on what it
  108.  * does.
  109.  *
  110.  * Results:
  111.  *      A standard Tcl result.
  112.  *
  113.  * Side effects:
  114.  *      See the user documentation.
  115.  *
  116.  *----------------------------------------------------------------------
  117.  */
  118. int
  119. Tk_ChooseColorObjCmd(
  120.     ClientData clientData, /* Main window associated with interpreter. */
  121.     Tcl_Interp *interp, /* Current interpreter. */
  122.     int objc, /* Number of arguments. */
  123.     Tcl_Obj *CONST objv[]) /* Argument objects. */
  124. {
  125.     Tk_Window parent;
  126.     char *title;
  127.     int i, picked, srcRead, dstWrote;
  128.     long response;
  129.     OSErr err;
  130.     static inited = 0;
  131.     static RGBColor in;
  132.     static CONST char *optionStrings[] = {
  133. "-initialcolor",    "-parent",     "-title",     NULL
  134.     };
  135.     enum options {
  136. COLOR_INITIAL,     COLOR_PARENT,   COLOR_TITLE
  137.     };
  138.     if (inited == 0) {
  139.      /*
  140.       * 'in' stores the last color picked.  The next time the color dialog
  141.       * pops up, the last color will remain in the dialog.
  142.       */
  143.       
  144.         in.red = 0xffff;
  145.         in.green = 0xffff;
  146.         in.blue = 0xffff;
  147.         inited = 1;
  148.     }
  149.     
  150.     parent = (Tk_Window) clientData;
  151.     title = "Choose a color:";
  152.     picked = 0;
  153.         
  154.     for (i = 1; i < objc; i += 2) {
  155.      int index;
  156.      char *option, *value;
  157.     
  158.         if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option",
  159. TCL_EXACT, &index) != TCL_OK) {
  160.     return TCL_ERROR;
  161. }
  162. if (i + 1 == objc) {
  163.     option = Tcl_GetStringFromObj(objv[i], NULL);
  164.     Tcl_AppendResult(interp, "value for "", option, "" missing", 
  165.     (char *) NULL);
  166.     return TCL_ERROR;
  167. }
  168. value = Tcl_GetStringFromObj(objv[i + 1], NULL);
  169. switch ((enum options) index) {
  170.     case COLOR_INITIAL: {
  171. XColor *colorPtr;
  172. colorPtr = Tk_GetColor(interp, parent, value);
  173. if (colorPtr == NULL) {
  174.     return TCL_ERROR;
  175. }
  176. in.red   = colorPtr->red;
  177. in.green = colorPtr->green;
  178.                 in.blue  = colorPtr->blue;
  179.                 Tk_FreeColor(colorPtr);
  180. break;
  181.     }
  182.     case COLOR_PARENT: {
  183. parent = Tk_NameToWindow(interp, value, parent);
  184. if (parent == NULL) {
  185.     return TCL_ERROR;
  186. }
  187. break;
  188.     }
  189.     case COLOR_TITLE: {
  190.         title = value;
  191. break;
  192.     }
  193. }
  194.     }
  195.         
  196.     /*
  197.      * Use the gestalt manager to determine how to bring
  198.      * up the color picker.  If versin 2.0 isn't available
  199.      * we can assume version 1.0 is available as it comes with
  200.      * Color Quickdraw which Tk requires to run at all.
  201.      */
  202.      
  203.     err = Gestalt(gestaltColorPicker, &response); 
  204.     if ((err == noErr) && (response == 0x0200L)) {
  205. ColorPickerInfo cpinfo;
  206.         /*
  207.          * Version 2.0 of the color picker is available. Let's use it
  208.          */
  209.      cpinfo.theColor.profile = 0L;
  210.      cpinfo.theColor.color.rgb.red   = in.red;
  211.      cpinfo.theColor.color.rgb.green = in.green;
  212.      cpinfo.theColor.color.rgb.blue  = in.blue;
  213.      cpinfo.dstProfile = 0L;
  214.      cpinfo.flags = kColorPickerCanModifyPalette | kColorPickerCanAnimatePalette;
  215.      cpinfo.placeWhere = kDeepestColorScreen;
  216.      cpinfo.pickerType = 0L;
  217.      cpinfo.eventProc = NULL;
  218.      cpinfo.colorProc = NULL;
  219.      cpinfo.colorProcData = NULL;
  220.     
  221.      Tcl_UtfToExternal(NULL, NULL, title, -1, 0, NULL, 
  222. StrBody(cpinfo.prompt), 255, &srcRead, &dstWrote, NULL);
  223.      StrLength(cpinfo.prompt) = (unsigned char) dstWrote;
  224.         if ((PickColor(&cpinfo) == noErr) && (cpinfo.newColorChosen != 0)) {
  225.             in.red  = cpinfo.theColor.color.rgb.red;
  226.             in.green  = cpinfo.theColor.color.rgb.green;
  227.             in.blue  = cpinfo.theColor.color.rgb.blue;
  228.             picked = 1;
  229.         }
  230.     } else {
  231.      RGBColor out;
  232.      Str255 prompt;
  233.      Point point = {-1, -1};
  234.     
  235.         /*
  236.          * Use version 1.0 of the color picker
  237.          */
  238.     
  239.      Tcl_UtfToExternal(NULL, NULL, title, -1, 0, NULL, StrBody(prompt), 
  240. 255, &srcRead, &dstWrote, NULL);
  241.      StrLength(prompt) = (unsigned char) dstWrote;
  242.         if (GetColor(point, prompt, &in, &out)) {
  243.             in = out;
  244.             picked = 1;
  245.         }
  246.     } 
  247.     
  248.     if (picked != 0) {
  249.         char result[32];
  250.         sprintf(result, "#%02x%02x%02x", in.red >> 8, in.green >> 8, 
  251.          in.blue >> 8);
  252. Tcl_AppendResult(interp, result, NULL);
  253.     }
  254.     return TCL_OK;
  255. }
  256. /*
  257.  *----------------------------------------------------------------------
  258.  *
  259.  * Tk_GetOpenFileObjCmd --
  260.  *
  261.  * This procedure implements the "open file" dialog box for the
  262.  * Mac platform. See the user documentation for details on what
  263.  * it does.
  264.  *
  265.  * Results:
  266.  *      A standard Tcl result.
  267.  *
  268.  * Side effects:
  269.  * See user documentation.
  270.  *----------------------------------------------------------------------
  271.  */
  272. int
  273. Tk_GetOpenFileObjCmd(
  274.     ClientData clientData, /* Main window associated with interpreter. */
  275.     Tcl_Interp *interp, /* Current interpreter. */
  276.     int objc, /* Number of arguments. */
  277.     Tcl_Obj *CONST objv[]) /* Argument objects. */
  278. {
  279.     int i, result, multiple;
  280.     OpenFileData ofd;
  281.     Tk_Window parent;
  282.     Str255 message, title;
  283.     AEDesc initialDesc = {typeNull, NULL};
  284.     FSSpec dirSpec;
  285.     static CONST char *openOptionStrings[] = {
  286.     "-defaultextension", "-filetypes", 
  287.     "-initialdir", "-initialfile", 
  288.     "-message", "-multiple",
  289.     "-parent", "-title",  NULL
  290.     };
  291.     enum openOptions {
  292.     OPEN_DEFAULT, OPEN_TYPES,
  293.     OPEN_INITDIR, OPEN_INITFILE,
  294.     OPEN_MESSAGE, OPEN_MULTIPLE, 
  295.     OPEN_PARENT, OPEN_TITLE
  296.     };
  297.     
  298.     if (!fileDlgInited) {
  299. InitFileDialogs();
  300.     }
  301.     
  302.     result = TCL_ERROR;    
  303.     parent = (Tk_Window) clientData; 
  304.     multiple = false;
  305.     title[0] = 0;
  306.     message[0] = 0;   
  307.     TkInitFileFilters(&ofd.fl);
  308.     
  309.     ofd.curType = 0;
  310.     ofd.popupItem = OPEN_POPUP_ITEM;
  311.     ofd.usePopup  = 1;
  312.     for (i = 1; i < objc; i += 2) {
  313.         char *choice;
  314. int index, choiceLen;
  315. char *string;
  316. int srcRead, dstWrote;
  317. if (Tcl_GetIndexFromObj(interp, objv[i], openOptionStrings, "option",
  318. TCL_EXACT, &index) != TCL_OK) {
  319.     result = TCL_ERROR;
  320.     goto end;
  321. }
  322. if (i + 1 == objc) {
  323.     string = Tcl_GetStringFromObj(objv[i], NULL);
  324.     Tcl_AppendResult(interp, "value for "", string, "" missing", 
  325.     (char *) NULL);
  326.     result = TCL_ERROR;
  327.     goto end;
  328. }
  329. switch (index) {
  330.     case OPEN_DEFAULT:
  331.         break;
  332.     case OPEN_TYPES:
  333.         choice = Tcl_GetStringFromObj(objv[i + 1], NULL);
  334.                 if (TkGetFileFilters(interp, &ofd.fl, choice, 0) 
  335.                         != TCL_OK) {
  336.                     result = TCL_ERROR;
  337.                     goto end;
  338.                 }
  339.         break;
  340.     case OPEN_INITDIR:
  341.         choice = Tcl_GetStringFromObj(objv[i + 1], NULL);
  342.                 if (HandleInitialDirectory(interp, choice, &dirSpec, 
  343.                         &initialDesc) != TCL_OK) {
  344.                     result = TCL_ERROR;
  345.                     goto end;
  346.                 }
  347.         break;
  348.     case OPEN_INITFILE:
  349.         break;
  350.     case OPEN_MESSAGE:
  351.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  352.         Tcl_UtfToExternal(NULL, NULL, choice, choiceLen, 
  353.         0, NULL, StrBody(message), 255, 
  354.         &srcRead, &dstWrote, NULL);
  355.                 message[0] = dstWrote;
  356.         break;
  357.     case OPEN_MULTIPLE:
  358.         if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &multiple) != TCL_OK) {
  359.             result = TCL_ERROR;
  360.             goto end;
  361.         }
  362.         break;
  363.     case OPEN_PARENT:
  364.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  365.                 parent = Tk_NameToWindow(interp, choice, parent);
  366.         if (parent == NULL) {
  367.             result = TCL_ERROR;
  368.             goto end;
  369.         }
  370.         break;
  371.     case OPEN_TITLE:
  372.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  373.         Tcl_UtfToExternal(NULL, NULL, choice, choiceLen, 
  374.         0, NULL, StrBody(title), 255, 
  375.         &srcRead, &dstWrote, NULL);
  376.                 title[0] = dstWrote;
  377.         break;
  378. }
  379.     }
  380.              
  381.     if (useNavServices) {
  382.         AEDesc *initialPtr = NULL;
  383.         
  384.         if (initialDesc.descriptorType == typeFSS) {
  385.             initialPtr = &initialDesc;
  386.         }
  387.         result = NavServicesGetFile(interp, &ofd, initialPtr, NULL, 
  388.                 title, message, multiple, OPEN_FILE);
  389.     } else {
  390.         result = StdGetFile(interp, &ofd, NULL, OPEN_FILE);
  391.     }
  392.     end:
  393.     TkFreeFileFilters(&ofd.fl);
  394.     AEDisposeDesc(&initialDesc);
  395.     
  396.     return result;
  397. }
  398. /*
  399.  *----------------------------------------------------------------------
  400.  *
  401.  * Tk_GetSaveFileObjCmd --
  402.  *
  403.  * Same as Tk_GetOpenFileCmd but opens a "save file" dialog box
  404.  * instead
  405.  *
  406.  * Results:
  407.  *      A standard Tcl result.
  408.  *
  409.  * Side effects:
  410.  * See user documentation.
  411.  *----------------------------------------------------------------------
  412.  */
  413. int
  414. Tk_GetSaveFileObjCmd(
  415.     ClientData clientData, /* Main window associated with interpreter. */
  416.     Tcl_Interp *interp, /* Current interpreter. */
  417.     int objc, /* Number of arguments. */
  418.     Tcl_Obj *CONST objv[]) /* Argument objects. */
  419. {
  420.     int i, result;
  421.     Str255 initialFile;
  422.     Tk_Window parent;
  423.     AEDesc initialDesc = {typeNull, NULL};
  424.     FSSpec dirSpec;
  425.     Str255 title, message;
  426.     OpenFileData ofd;
  427.     static CONST char *saveOptionStrings[] = {
  428.     "-defaultextension", "-filetypes", "-initialdir", "-initialfile", 
  429.     "-message", "-parent", "-title",  NULL
  430.     };
  431.     enum saveOptions {
  432.     SAVE_DEFAULT, SAVE_TYPES, SAVE_INITDIR, SAVE_INITFILE,
  433.     SAVE_MESSAGE, SAVE_PARENT, SAVE_TITLE
  434.     };
  435.     if (!fileDlgInited) {
  436. InitFileDialogs();
  437.     }
  438.     
  439.     result = TCL_ERROR;    
  440.     parent = (Tk_Window) clientData;    
  441.     StrLength(initialFile) = 0;
  442.     title[0] = 0;
  443.     message[0] = 0;   
  444.     
  445.     for (i = 1; i < objc; i += 2) {
  446.         char *choice;
  447. int index, choiceLen;
  448. char *string;
  449.         Tcl_DString ds;
  450.         int srcRead, dstWrote;
  451. if (Tcl_GetIndexFromObj(interp, objv[i], saveOptionStrings, "option",
  452. TCL_EXACT, &index) != TCL_OK) {
  453.     return TCL_ERROR;
  454. }
  455. if (i + 1 == objc) {
  456.     string = Tcl_GetStringFromObj(objv[i], NULL);
  457.     Tcl_AppendResult(interp, "value for "", string, "" missing", 
  458.     (char *) NULL);
  459.     return TCL_ERROR;
  460. }
  461. switch (index) {
  462.     case SAVE_DEFAULT:
  463.         break;
  464.     case SAVE_TYPES:
  465.         break;
  466.     case SAVE_INITDIR:
  467.         choice = Tcl_GetStringFromObj(objv[i + 1], NULL);
  468.                 if (HandleInitialDirectory(interp, choice, &dirSpec, 
  469.                         &initialDesc) != TCL_OK) {
  470.                     result = TCL_ERROR;
  471.                     goto end;
  472.                 }
  473.         break;
  474.     case SAVE_INITFILE:
  475.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  476.                 if (Tcl_TranslateFileName(interp, choice, &ds) == NULL) {
  477.                     result = TCL_ERROR;
  478.                     goto end;
  479.                 }
  480.                 Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), 
  481.                  Tcl_DStringLength(&ds), 0, NULL, 
  482.         StrBody(initialFile), 255, &srcRead, &dstWrote, NULL);
  483.                 StrLength(initialFile) = (unsigned char) dstWrote;
  484.                 Tcl_DStringFree(&ds);            
  485.         break;
  486.     case SAVE_MESSAGE:
  487.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  488.         Tcl_UtfToExternal(NULL, NULL, choice, choiceLen, 
  489.         0, NULL, StrBody(message), 255, 
  490.         &srcRead, &dstWrote, NULL);
  491.                 StrLength(message) = (unsigned char) dstWrote;
  492.         break;
  493.     case SAVE_PARENT:
  494.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  495.                 parent = Tk_NameToWindow(interp, choice, parent);
  496.         if (parent == NULL) {
  497.             result = TCL_ERROR;
  498.             goto end;
  499.         }
  500.         break;
  501.     case SAVE_TITLE:
  502.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  503.         Tcl_UtfToExternal(NULL, NULL, choice, choiceLen, 
  504.         0, NULL, StrBody(title), 255, 
  505.         &srcRead, &dstWrote, NULL);
  506.                 StrLength(title) = (unsigned char) dstWrote;
  507.         break;
  508. }
  509.     }
  510.          
  511.     TkInitFileFilters(&ofd.fl);
  512.     ofd.usePopup = 0;
  513.     if (useNavServices) {
  514.         AEDesc *initialPtr = NULL;
  515.         
  516.         if (initialDesc.descriptorType == typeFSS) {
  517.             initialPtr = &initialDesc;
  518.         }
  519.         result = NavServicesGetFile(interp, &ofd, initialPtr, initialFile, 
  520.                 title, message, false, SAVE_FILE);
  521.     } else {
  522.         result = StdGetFile(interp, NULL, initialFile, SAVE_FILE);
  523.     }
  524.     end:
  525.     
  526.     AEDisposeDesc(&initialDesc);
  527.     
  528.     return result;
  529. }
  530. /*
  531.  *----------------------------------------------------------------------
  532.  *
  533.  * Tk_ChooseDirectoryObjCmd --
  534.  *
  535.  * This procedure implements the "tk_chooseDirectory" dialog box 
  536.  * for the Windows platform. See the user documentation for details 
  537.  * on what it does.
  538.  *
  539.  * Results:
  540.  * See user documentation.
  541.  *
  542.  * Side effects:
  543.  * A modal dialog window is created.  Tcl_SetServiceMode() is
  544.  * called to allow background events to be processed
  545.  *
  546.  *----------------------------------------------------------------------
  547.  */
  548. int
  549. Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv)
  550.     ClientData clientData; /* Main window associated with interpreter. */
  551.     Tcl_Interp *interp; /* Current interpreter. */
  552.     int objc; /* Number of arguments. */
  553.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  554. {
  555.     int i, result;
  556.     Tk_Window parent;
  557.     AEDesc initialDesc = {typeNull, NULL};
  558.     FSSpec dirSpec;
  559.     Str255 message, title;
  560.     int srcRead, dstWrote;
  561.     OpenFileData ofd;
  562.     static CONST char *chooseOptionStrings[] = {
  563.     "-initialdir", "-message", "-mustexist", "-parent", "-title", NULL
  564.     };
  565.     enum chooseOptions {
  566.     CHOOSE_INITDIR, CHOOSE_MESSAGE, CHOOSE_MUSTEXIST, 
  567.     CHOOSE_PARENT, CHOOSE_TITLE
  568.     };
  569.   
  570.     
  571.     if (!NavServicesAvailable()) {
  572.         return TCL_ERROR;
  573.     }
  574.     if (!fileDlgInited) {
  575. InitFileDialogs();
  576.     }
  577.     result = TCL_ERROR;    
  578.     parent = (Tk_Window) clientData;    
  579.     title[0] = 0;
  580.     message[0] = 0;   
  581.     for (i = 1; i < objc; i += 2) {
  582.         char *choice;
  583. int index, choiceLen;
  584. char *string;
  585. if (Tcl_GetIndexFromObj(interp, objv[i], chooseOptionStrings, "option",
  586. TCL_EXACT, &index) != TCL_OK) {
  587.     return TCL_ERROR;
  588. }
  589. if (i + 1 == objc) {
  590.     string = Tcl_GetStringFromObj(objv[i], NULL);
  591.     Tcl_AppendResult(interp, "value for "", string, "" missing", 
  592.     (char *) NULL);
  593.     return TCL_ERROR;
  594. }
  595. switch (index) {
  596.     case CHOOSE_INITDIR:
  597.         choice = Tcl_GetStringFromObj(objv[i + 1], NULL);
  598.                 if (HandleInitialDirectory(interp, choice, &dirSpec, 
  599.                         &initialDesc) != TCL_OK) {
  600.                     result = TCL_ERROR;
  601.                     goto end;
  602.                 }
  603.         break;
  604.     case CHOOSE_MESSAGE:
  605.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  606.         Tcl_UtfToExternal(NULL, NULL, choice, choiceLen, 
  607.         0, NULL, StrBody(message), 255, 
  608.         &srcRead, &dstWrote, NULL);
  609.                 StrLength(message) = (unsigned char) dstWrote;
  610.         break;
  611.     case CHOOSE_PARENT:
  612.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  613.                 parent = Tk_NameToWindow(interp, choice, parent);
  614.         if (parent == NULL) {
  615.             result = TCL_ERROR;
  616.             goto end;
  617.         }
  618.         break;
  619.     case CHOOSE_TITLE:
  620.         choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
  621.         Tcl_UtfToExternal(NULL, NULL, choice, choiceLen, 
  622.         0, NULL, StrBody(title), 255, 
  623.         &srcRead, &dstWrote, NULL);
  624.                 StrLength(title) = (unsigned char) dstWrote;
  625.         break;
  626. }
  627.     }
  628.              
  629.     TkInitFileFilters(&ofd.fl);
  630.     ofd.usePopup = 0;
  631.     if (useNavServices) {
  632.         AEDesc *initialPtr = NULL;
  633.         
  634.         if (initialDesc.descriptorType == typeFSS) {
  635.             initialPtr = &initialDesc;
  636.         }
  637.         result = NavServicesGetFile(interp, &ofd, initialPtr, NULL, 
  638.                 title, message, false, CHOOSE_FOLDER);
  639.     } else {
  640.         result = TCL_ERROR;
  641.     }
  642.     end:
  643.     AEDisposeDesc(&initialDesc);
  644.     
  645.     return result;
  646. }
  647. int
  648. HandleInitialDirectory (
  649.     Tcl_Interp *interp,
  650.     char *initialDir, 
  651.     FSSpec *dirSpec, 
  652.     AEDesc *dirDescPtr)
  653. {
  654. Tcl_DString ds;
  655. long dirID;
  656. OSErr err;
  657. Boolean isDirectory;
  658. Str255 dir;
  659. int srcRead, dstWrote;
  660. if (Tcl_TranslateFileName(interp, initialDir, &ds) == NULL) {
  661.     return TCL_ERROR;
  662. }
  663. Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), 
  664. Tcl_DStringLength(&ds), 0, NULL, StrBody(dir), 255, 
  665. &srcRead, &dstWrote, NULL);
  666.         StrLength(dir) = (unsigned char) dstWrote;
  667. Tcl_DStringFree(&ds);
  668.           
  669. err = FSpLocationFromPath(StrLength(dir), StrBody(dir), dirSpec);
  670. if (err != noErr) {
  671.     Tcl_AppendResult(interp, "bad directory "", initialDir, """, NULL);
  672.     return TCL_ERROR;
  673. }
  674. err = FSpGetDirectoryIDTcl(dirSpec, &dirID, &isDirectory);
  675. if ((err != noErr) || !isDirectory) {
  676.     Tcl_AppendResult(interp, "bad directory "", initialDir, """, NULL);
  677.     return TCL_ERROR;
  678. }
  679.         if (useNavServices) {
  680.             AECreateDesc( typeFSS, dirSpec, sizeof(*dirSpec), dirDescPtr);        
  681.         } else {
  682.     /*
  683.      * Make sure you negate -dirSpec.vRefNum because the 
  684.      * standard file package wants it that way !
  685.      */
  686.     LMSetSFSaveDisk(-dirSpec->vRefNum);
  687.     LMSetCurDirStore(dirID);
  688. }
  689.         return TCL_OK;
  690. }
  691. static void
  692. InitFileDialogs()
  693. {
  694.     fileDlgInited = 1;
  695.     
  696.     if (NavServicesAvailable()) {
  697.         openFileFilterUPP = NewNavObjectFilterProc(OpenFileFilterProc);
  698.         openFileEventUPP = NewNavEventProc(OpenEventProc);
  699.         useNavServices = 1;
  700.     } else {
  701. openFilter = NewFileFilterYDProc(FileFilterProc);
  702. openHook = NewDlgHookYDProc(OpenHookProc);
  703. saveHook = NewDlgHookYDProc(OpenHookProc);
  704. useNavServices = 0;
  705.     }
  706.     
  707.         
  708. }
  709. /*
  710.  *----------------------------------------------------------------------
  711.  *
  712.  * GetFileName --
  713.  *
  714.  * Calls the Mac file dialog functions for the user to choose a
  715.  * file to or save.
  716.  *
  717.  * Results:
  718.  * A standard Tcl result.
  719.  *
  720.  * Side effects:
  721.  * If the user selects a file, the native pathname of the file
  722.  * is returned in the interp's result. Otherwise an empty string
  723.  * is returned in the interp's result.
  724.  *
  725.  *----------------------------------------------------------------------
  726.  */
  727. static int
  728. GetFileName(
  729.     ClientData clientData, /* Main window associated with interpreter. */
  730.     Tcl_Interp *interp, /* Current interpreter. */
  731.     int objc, /* Number of arguments. */
  732.     Tcl_Obj *CONST objv[], /* Argument objects. */
  733.     int isOpen) /* true if we should call GetOpenFileName(),
  734.  * false if we should call GetSaveFileName() */
  735. {
  736.     return TCL_OK;
  737. }
  738. static int
  739. NavServicesGetFile(
  740.     Tcl_Interp *interp,
  741.     OpenFileData *ofdPtr,
  742.     AEDesc *initialDesc,
  743.     unsigned char *initialFile,
  744.     StringPtr title,
  745.     StringPtr message,
  746.     int multiple,
  747.     int isOpen)
  748. {
  749.     NavReplyRecord theReply;
  750.     NavDialogOptions diagOptions;
  751.     OSErr err;
  752.     Tcl_Obj *theResult;
  753.     int result;
  754.     
  755.     diagOptions.location.h = -1;
  756.     diagOptions.location.v = -1;
  757.     diagOptions.dialogOptionFlags = kNavDontAutoTranslate 
  758.             + kNavDontAddTranslateItems;
  759.             
  760.     if (multiple) {
  761.         diagOptions.dialogOptionFlags += kNavAllowMultipleFiles;
  762.     }
  763.     
  764.     if (ofdPtr != NULL && ofdPtr->usePopup) {
  765.         FileFilter *filterPtr;
  766.         
  767. filterPtr = ofdPtr->fl.filters;
  768. if (filterPtr == NULL) {
  769.     ofdPtr->usePopup = 0;
  770. }
  771.     }
  772.     
  773.     if (ofdPtr != NULL && ofdPtr->usePopup) {    
  774.         NavMenuItemSpecHandle popupExtensionHandle = NULL;
  775.         NavMenuItemSpec *popupItems;
  776.         FileFilter *filterPtr;
  777.         short index = 0;
  778. ofdPtr->curType = 0;
  779.         popupExtensionHandle = (NavMenuItemSpecHandle) NewHandle(ofdPtr->fl.numFilters 
  780.                 * sizeof(NavMenuItemSpec));
  781.         HLock((Handle) popupExtensionHandle);
  782.         popupItems = *popupExtensionHandle;
  783.         
  784.         for (filterPtr = ofdPtr->fl.filters; filterPtr != NULL; 
  785.                 filterPtr = filterPtr->next, popupItems++, index++) {
  786.             int len;
  787.             
  788.             len = strlen(filterPtr->name);
  789.             BlockMove(filterPtr->name, popupItems->menuItemName + 1, len);
  790.             popupItems->menuItemName[0] = len;
  791.             popupItems->menuCreator = 'WIsH';
  792.             popupItems->menuType = index;
  793.         }
  794.         HUnlock((Handle) popupExtensionHandle);
  795.         diagOptions.popupExtension = popupExtensionHandle;
  796.     } else {        
  797.         diagOptions.dialogOptionFlags += kNavNoTypePopup; 
  798.         diagOptions.popupExtension = NULL;
  799.     }
  800.         
  801.     if ((initialFile != NULL) && (initialFile[0] != 0)) {
  802.         char *lastColon;
  803.         int len;
  804.         
  805.         len = initialFile[0];
  806.         
  807.         p2cstr(initialFile);        
  808.         lastColon = strrchr((char *)initialFile, ':');
  809.         if (lastColon != NULL) {
  810.             len -= lastColon - ((char *) (initialFile + 1));
  811.             BlockMove(lastColon + 1, diagOptions.savedFileName + 1, len);
  812.             diagOptions.savedFileName[0] = len;
  813.         } else {  
  814.             BlockMove(initialFile, diagOptions.savedFileName + 1, len);
  815.             diagOptions.savedFileName[0] = len;
  816.         }
  817.     } else {
  818.         diagOptions.savedFileName[0] = 0;
  819.     }
  820.     
  821.     strcpy((char *) (diagOptions.clientName + 1),"Wish");
  822.     diagOptions.clientName[0] = strlen("Wish");
  823.     
  824.     if (title == NULL) {
  825.         diagOptions.windowTitle[0] = 0;
  826.     } else {
  827.         BlockMove(title, diagOptions.windowTitle, title[0] + 1);
  828.         diagOptions.windowTitle[0] = title[0];
  829.     }
  830.     
  831.     if (message == NULL) {
  832.         diagOptions.message[0] = 0;
  833.     } else {
  834.         BlockMove(message, diagOptions.message, message[0] + 1);
  835.         diagOptions.message[0] = message[0];
  836.     }
  837.     
  838.     diagOptions.actionButtonLabel[0] = 0;
  839.     diagOptions.cancelButtonLabel[0] = 0;
  840.     diagOptions.preferenceKey = 0;
  841.     
  842.     /* Now process the selection list.  We have to use the popupExtension
  843.      * to fill the menu.
  844.      */
  845.     
  846.     
  847.     if (isOpen == OPEN_FILE) {
  848.         err = NavGetFile(initialDesc, &theReply, &diagOptions, openFileEventUPP,  
  849.                 NULL, openFileFilterUPP, NULL, ofdPtr);    
  850.     } else if (isOpen == SAVE_FILE) {
  851.         err = NavPutFile (initialDesc, &theReply, &diagOptions, openFileEventUPP, 
  852.                 'TEXT', 'WIsH', NULL);
  853.     } else if (isOpen == CHOOSE_FOLDER) {
  854.         err = NavChooseFolder (initialDesc, &theReply, &diagOptions,
  855.                 openFileEventUPP, NULL, NULL);
  856.     }
  857.     
  858.                         
  859.     /*
  860.      * Most commands assume that the file dialogs return a single
  861.      * item, not a list.  So only build a list if multiple is true...
  862.      */
  863.                          
  864.     if (multiple) {
  865.         theResult = Tcl_NewListObj(0, NULL);
  866.     } else {
  867.         theResult = Tcl_NewObj();
  868.     }
  869.            
  870.     if ( theReply.validRecord && err == noErr ) {
  871.         AEDesc resultDesc;
  872.         long count;
  873.         Tcl_DString fileName;
  874.         Handle pathHandle;
  875.         int length;
  876.         
  877.         if ( err == noErr ) {
  878.             err = AECountItems(&(theReply.selection), &count);
  879.             if (err == noErr) {
  880.                 long i;
  881.                 for (i = 1; i <= count; i++ ) {
  882.                     err = AEGetNthDesc(&(theReply.selection),
  883.                             i, typeFSS, NULL, &resultDesc);
  884.                     if (err == noErr) {
  885.                         HLock(resultDesc.dataHandle);
  886.                         pathHandle = NULL;
  887.                         FSpPathFromLocation((FSSpec *) *resultDesc.dataHandle, 
  888.                                 &length, &pathHandle);
  889.                         HLock(pathHandle);
  890.                         Tcl_ExternalToUtfDString(NULL, (char *) *pathHandle, -1, &fileName);
  891.                         if (multiple) {
  892.                             Tcl_ListObjAppendElement(interp, theResult, 
  893.                                     Tcl_NewStringObj(Tcl_DStringValue(&fileName), 
  894.                                     Tcl_DStringLength(&fileName)));
  895.                         } else {
  896.                             Tcl_SetStringObj(theResult, Tcl_DStringValue(&fileName), 
  897.                                     Tcl_DStringLength(&fileName));
  898.                         }
  899.                         
  900.                         Tcl_DStringFree(&fileName);
  901.                         HUnlock(pathHandle);
  902.                         DisposeHandle(pathHandle);
  903.                         HUnlock(resultDesc.dataHandle);
  904.                         AEDisposeDesc( &resultDesc );
  905.                     }
  906.                 }
  907.             }
  908.          }
  909.          err = NavDisposeReply( &theReply );
  910.          Tcl_SetObjResult(interp, theResult);
  911.          result = TCL_OK;
  912.     } else if (err == userCanceledErr) {
  913.         result = TCL_OK;
  914.     } else {
  915.         result = TCL_ERROR;
  916.     }
  917.     
  918.     if (diagOptions.popupExtension != NULL) {
  919.         DisposeHandle((Handle) diagOptions.popupExtension);
  920.     }
  921.     
  922.     return result;
  923. }
  924. static pascal Boolean 
  925. OpenFileFilterProc( 
  926.     AEDesc* theItem, void* info,
  927.     NavCallBackUserData callBackUD,
  928.     NavFilterModes filterMode )
  929. {
  930.     OpenFileData *ofdPtr = (OpenFileData *) callBackUD;
  931.     if (!ofdPtr->usePopup) {
  932.         return true;
  933.     } else {
  934.         if (ofdPtr->fl.numFilters == 0) {
  935.             return true;
  936.         } else {
  937.             
  938.             if ( theItem->descriptorType == typeFSS ) {
  939.                 NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*)info;
  940.                 int result;
  941.                 
  942.                 if ( !theInfo->isFolder ) {
  943.                     OSType fileType;
  944.                     StringPtr fileNamePtr;
  945.                     int i;
  946.                     FileFilter *filterPtr;
  947.                
  948.                     fileType = theInfo->fileAndFolder.fileInfo.finderInfo.fdType;
  949.                     HLock(theItem->dataHandle);
  950.                     fileNamePtr = (((FSSpec *) *theItem->dataHandle)->name);
  951.                     
  952.                     if (ofdPtr->usePopup) {
  953.                         i = ofdPtr->curType;
  954.                 for (filterPtr=ofdPtr->fl.filters; filterPtr && i>0; i--) {
  955.                     filterPtr = filterPtr->next;
  956.                 }
  957.                 if (filterPtr) {
  958.                     result = MatchOneType(fileNamePtr, fileType,
  959.                             ofdPtr, filterPtr);
  960.                 } else {
  961.                     result = false;
  962.                         }
  963.                     } else {
  964.                 /*
  965.                  * We are not using the popup menu. In this case, the file is
  966.                  * considered matched if it matches any of the file filters.
  967.                  */
  968. result = UNMATCHED;
  969.                 for (filterPtr=ofdPtr->fl.filters; filterPtr;
  970.                 filterPtr=filterPtr->next) {
  971.                     if (MatchOneType(fileNamePtr, fileType,
  972.                             ofdPtr, filterPtr) == MATCHED) {
  973.                         result = MATCHED;
  974.                         break;
  975.                     }
  976.                 }
  977.                     }
  978.                     
  979.                     HUnlock(theItem->dataHandle);
  980.                     return (result == MATCHED);
  981.                 } else {
  982.                     return true;
  983.                 }
  984.             }
  985.         }
  986.         
  987.         return true;
  988.     }
  989. }
  990. pascal void 
  991. OpenEventProc(
  992.     NavEventCallbackMessage callBackSelector,
  993.     NavCBRecPtr callBackParams,
  994.     NavCallBackUserData callBackUD )
  995. {
  996.     NavMenuItemSpec *chosenItem;
  997.     OpenFileData *ofd = (OpenFileData *) callBackUD;
  998.         
  999.     if (callBackSelector ==  kNavCBPopupMenuSelect) {
  1000.         chosenItem = (NavMenuItemSpec *) callBackParams->eventData.eventDataParms.param;
  1001.         ofd->curType = chosenItem->menuType;
  1002.     } else if (callBackSelector == kNavCBEvent) {
  1003.      if (callBackParams->eventData.eventDataParms.event->what == updateEvt) {
  1004.      if (TkMacConvertEvent( callBackParams->eventData.eventDataParms.event)) {
  1005.          while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT|TCL_WINDOW_EVENTS)) {
  1006.             /* Empty Body */
  1007.          }
  1008.          }
  1009.         }
  1010.     }
  1011. }
  1012. static int
  1013. StdGetFile(
  1014.     Tcl_Interp *interp,
  1015.     OpenFileData *ofd,
  1016.     unsigned char *initialFile,
  1017.     int isOpen)
  1018. {
  1019.     int i;
  1020.     StandardFileReply reply;
  1021.     Point mypoint;
  1022.     MenuHandle menu = NULL;
  1023.     /*
  1024.      * Set the items in the file types popup.
  1025.      */
  1026.     /*
  1027.      * Delete all the entries inside the popup menu, in case there's any
  1028.      * left overs from previous invocation of this command
  1029.      */
  1030.     if (ofd != NULL && ofd->usePopup) {
  1031. FileFilter *filterPtr;
  1032. menu = GetMenu(OPEN_MENU);
  1033.         for (i = CountMItems(menu); i > 0; i--) {
  1034.             /*
  1035.              * The item indices are one based. Also, if we delete from
  1036.              * the beginning, the items may be re-numbered. So we
  1037.              * delete from the end
  1038.           */
  1039.           
  1040.           DeleteMenuItem(menu, i);
  1041.         }
  1042. filterPtr = ofd->fl.filters;
  1043. if (filterPtr == NULL) {
  1044.     ofd->usePopup = 0;
  1045. } else {
  1046.     for ( ; filterPtr != NULL; filterPtr = filterPtr->next) {
  1047.         Str255 str;
  1048.         
  1049.      StrLength(str) = (unsigned char) strlen(filterPtr->name);
  1050.      strcpy(StrBody(str), filterPtr->name);
  1051. AppendMenu(menu, str);
  1052.     }
  1053. }
  1054.     }
  1055.     /*
  1056.      * Call the toolbox file dialog function.
  1057.      */
  1058.      
  1059.     SetPt(&mypoint, -1, -1);
  1060.     TkpSetCursor(NULL);
  1061.     if (isOpen == OPEN_FILE) {
  1062.         if (ofd != NULL && ofd->usePopup) {
  1063.     CustomGetFile(openFilter, (short) -1, NULL, &reply, OPEN_BOX,
  1064.          mypoint, openHook, NULL, NULL, NULL, (void*) ofd);
  1065. } else {
  1066.     StandardGetFile(NULL, -1, NULL, &reply);
  1067. }
  1068.     } else if (isOpen == SAVE_FILE) {
  1069. static Str255 prompt = "pSave as";
  1070.     if (ofd != NULL && ofd->usePopup) {
  1071.         /*
  1072.          * Currently this never gets called because we don't use
  1073.          * popup for the save dialog.
  1074.          */
  1075.     CustomPutFile(prompt, initialFile, &reply, OPEN_BOX, 
  1076.     mypoint, saveHook, NULL, NULL, NULL, (void *) ofd);
  1077. } else {
  1078.     StandardPutFile(prompt, initialFile, &reply);
  1079. }
  1080.     }
  1081.     /*
  1082.      * Now parse the reply, and populate the Tcl result.
  1083.      */
  1084.      
  1085.     if (reply.sfGood) {
  1086.         int length;
  1087.      Handle pathHandle;
  1088.     
  1089.      pathHandle = NULL;
  1090.      FSpPathFromLocation(&reply.sfFile, &length, &pathHandle);
  1091. if (pathHandle != NULL) {
  1092.     Tcl_DString ds;
  1093.     
  1094.     HLock(pathHandle);
  1095.     Tcl_ExternalToUtfDString(NULL, (char *) *pathHandle, -1, &ds);
  1096.     Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);
  1097.     Tcl_DStringFree(&ds);
  1098.     HUnlock(pathHandle);
  1099.     DisposeHandle(pathHandle);
  1100. }
  1101.     }
  1102.     
  1103.     if (menu != NULL) {
  1104.      DisposeMenu(menu);
  1105.     }
  1106.     return TCL_OK;
  1107. }
  1108. /*
  1109.  *----------------------------------------------------------------------
  1110.  *
  1111.  * OpenHookProc --
  1112.  *
  1113.  * Gets called for various events that occur in the file dialog box.
  1114.  * Initializes the popup menu or rebuild the file list depending on
  1115.  * the type of the event.
  1116.  *
  1117.  * Results:
  1118.  * A standard result understood by the Mac file dialog event dispatcher.
  1119.  *
  1120.  * Side effects:
  1121.  * The contents in the file dialog may be changed depending on
  1122.  * the type of the event.
  1123.  *----------------------------------------------------------------------
  1124.  */
  1125. static pascal short
  1126. OpenHookProc(
  1127.     short item, /* Event description. */
  1128.     DialogPtr theDialog, /* The dialog where the event occurs. */
  1129.     OpenFileData *ofdPtr) /* Information about the file dialog. */
  1130. {
  1131.     short ignore;
  1132.     Rect rect;
  1133.     Handle handle;
  1134.     int newType;
  1135.     switch (item) {
  1136. case sfHookFirstCall:
  1137.     if (ofdPtr->usePopup) {
  1138. /*
  1139.  * Set the popup list to display the selected type.
  1140.  */
  1141. GetDialogItem(theDialog, ofdPtr->popupItem, &ignore, &handle, 
  1142. &rect);
  1143. SetControlValue((ControlRef) handle, ofdPtr->curType + 1);
  1144.     }
  1145.     return sfHookNullEvent;
  1146.       
  1147. case OPEN_POPUP_ITEM:
  1148.     if (ofdPtr->usePopup) {
  1149. GetDialogItem(theDialog, ofdPtr->popupItem,
  1150. &ignore, &handle, &rect);
  1151. newType = GetControlValue((ControlRef) handle) - 1;
  1152. if (ofdPtr->curType != newType) {
  1153.     if (newType<0 || newType>ofdPtr->fl.numFilters) {
  1154. /*
  1155.  * Sanity check. Looks like the user selected an
  1156.  * non-existent menu item?? Don't do anything.
  1157.  */
  1158.     } else {
  1159. ofdPtr->curType = newType;
  1160.     }
  1161.     return sfHookRebuildList;
  1162. }
  1163.     }  
  1164.     break;
  1165.     }
  1166.     return item;
  1167. }
  1168. /*
  1169.  *----------------------------------------------------------------------
  1170.  *
  1171.  * FileFilterProc --
  1172.  *
  1173.  * Filters files according to file types. Get called whenever the
  1174.  * file list needs to be updated inside the dialog box.
  1175.  *
  1176.  * Results:
  1177.  * Returns MATCHED if the file should be shown in the listbox, returns
  1178.  * UNMATCHED otherwise.
  1179.  *
  1180.  * Side effects:
  1181.  * If MATCHED is returned, the file is shown in the listbox.
  1182.  *
  1183.  *----------------------------------------------------------------------
  1184.  */
  1185. static pascal Boolean
  1186. FileFilterProc(
  1187.     CInfoPBPtr pb, /* Information about the file */
  1188.     void *myData) /* Client data for this file dialog */
  1189. {
  1190.     int i;
  1191.     OpenFileData * ofdPtr = (OpenFileData*)myData;
  1192.     FileFilter * filterPtr;
  1193.     if (ofdPtr->fl.numFilters == 0) {
  1194. /*
  1195.  * No types have been specified. List all files by default
  1196.  */
  1197. return MATCHED;
  1198.     }
  1199.     if (pb->dirInfo.ioFlAttrib & 0x10) {
  1200.      /*
  1201.       * This is a directory: always show it
  1202.       */
  1203.      return MATCHED;
  1204.     }
  1205.     if (ofdPtr->usePopup) {
  1206.         i = ofdPtr->curType;
  1207. for (filterPtr=ofdPtr->fl.filters; filterPtr && i>0; i--) {
  1208.     filterPtr = filterPtr->next;
  1209. }
  1210. if (filterPtr) {
  1211.     return MatchOneType(pb->hFileInfo.ioNamePtr, pb->hFileInfo.ioFlFndrInfo.fdType,
  1212.             ofdPtr, filterPtr);
  1213. } else {
  1214.     return UNMATCHED;
  1215.         }
  1216.     } else {
  1217. /*
  1218.  * We are not using the popup menu. In this case, the file is
  1219.  * considered matched if it matches any of the file filters.
  1220.  */
  1221. for (filterPtr=ofdPtr->fl.filters; filterPtr;
  1222. filterPtr=filterPtr->next) {
  1223.     if (MatchOneType(pb->hFileInfo.ioNamePtr, pb->hFileInfo.ioFlFndrInfo.fdType,
  1224.             ofdPtr, filterPtr) == MATCHED) {
  1225.         return MATCHED;
  1226.     }
  1227. }
  1228. return UNMATCHED;
  1229.     }
  1230. }
  1231. /*
  1232.  *----------------------------------------------------------------------
  1233.  *
  1234.  * MatchOneType --
  1235.  *
  1236.  * Match a file with one file type in the list of file types.
  1237.  *
  1238.  * Results:
  1239.  * Returns MATCHED if the file matches with the file type; returns
  1240.  * UNMATCHED otherwise.
  1241.  *
  1242.  * Side effects:
  1243.  * None
  1244.  *
  1245.  *----------------------------------------------------------------------
  1246.  */
  1247. static Boolean
  1248. MatchOneType(
  1249.     StringPtr fileNamePtr, /* Name of the file */
  1250.     OSType    fileType,         /* Type of the file */ 
  1251.     OpenFileData * ofdPtr, /* Information about this file dialog */
  1252.     FileFilter * filterPtr) /* Match the file described by pb against
  1253.  * this filter */
  1254. {
  1255.     FileFilterClause * clausePtr;
  1256.     /*
  1257.      * A file matches with a file type if it matches with at least one
  1258.      * clause of the type.
  1259.      *
  1260.      * If the clause has both glob patterns and ostypes, the file must
  1261.      * match with at least one pattern AND at least one ostype.
  1262.      *
  1263.      * If the clause has glob patterns only, the file must match with at least
  1264.      * one pattern.
  1265.      *
  1266.      * If the clause has mac types only, the file must match with at least
  1267.      * one mac type.
  1268.      *
  1269.      * If the clause has neither glob patterns nor mac types, it's
  1270.      * considered an error.
  1271.      */
  1272.     for (clausePtr=filterPtr->clauses; clausePtr; clausePtr=clausePtr->next) {
  1273. int macMatched  = 0;
  1274. int globMatched = 0;
  1275. GlobPattern * globPtr;
  1276. MacFileType * mfPtr;
  1277. if (clausePtr->patterns == NULL) {
  1278.     globMatched = 1;
  1279. }
  1280. if (clausePtr->macTypes == NULL) {
  1281.     macMatched = 1;
  1282. }
  1283. for (globPtr=clausePtr->patterns; globPtr; globPtr=globPtr->next) {
  1284.     char filename[256];
  1285.     int len;
  1286.     char * p, *q, *ext;
  1287.         
  1288.     if (fileNamePtr == NULL) {
  1289. continue;
  1290.     }
  1291.     p = (char*)(fileNamePtr);
  1292.     len = p[0];
  1293.     strncpy(filename, p+1, len);
  1294.     filename[len] = '';
  1295.     ext = globPtr->pattern;
  1296.     if (ext[0] == '') {
  1297. /*
  1298.  * We don't want any extensions: OK if the filename doesn't
  1299.  * have "." in it
  1300.  */
  1301. for (q=filename; *q; q++) {
  1302.     if (*q == '.') {
  1303. goto glob_unmatched;
  1304.     }
  1305. }
  1306. goto glob_matched;
  1307.     }
  1308.         
  1309.     if (Tcl_StringMatch(filename, ext)) {
  1310. goto glob_matched;
  1311.     } else {
  1312. goto glob_unmatched;
  1313.     }
  1314.   glob_unmatched:
  1315.     continue;
  1316.   glob_matched:
  1317.     globMatched = 1;
  1318.     break;
  1319. }
  1320. for (mfPtr=clausePtr->macTypes; mfPtr; mfPtr=mfPtr->next) {
  1321.     if (fileType == mfPtr->type) {
  1322. macMatched = 1;
  1323. break;
  1324.     }
  1325.         }
  1326. if (globMatched && macMatched) {
  1327.     return MATCHED;
  1328. }
  1329.     }
  1330.     return UNMATCHED;
  1331. }