/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwindialog.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwindialog.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 70 by dashley, Sat Nov 5 10:54:17 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2    
3  /*  /*
4   * tkWinDialog.c --   * tkWinDialog.c --
5   *   *
6   *      Contains the Windows implementation of the common dialog boxes.   *      Contains the Windows implementation of the common dialog boxes.
7   *   *
8   * Copyright (c) 1996-1997 Sun Microsystems, Inc.   * Copyright (c) 1996-1997 Sun Microsystems, Inc.
9   *   *
10   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
11   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12   *   *
13   * RCS: @(#) $Id: tkwindialog.c,v 1.1.1.1 2001/06/13 05:12:25 dtashley Exp $   * RCS: @(#) $Id: tkwindialog.c,v 1.1.1.1 2001/06/13 05:12:25 dtashley Exp $
14   *   *
15   */   */
16    
17  #include "tkWinInt.h"  #include "tkWinInt.h"
18  #include "tkFileFilter.h"  #include "tkFileFilter.h"
19    
20  #include <commdlg.h>    /* includes common dialog functionality */  #include <commdlg.h>    /* includes common dialog functionality */
21  #include <dlgs.h>       /* includes common dialog template defines */  #include <dlgs.h>       /* includes common dialog template defines */
22  #include <cderr.h>      /* includes the common dialog error codes */  #include <cderr.h>      /* includes the common dialog error codes */
23    
24  typedef struct ThreadSpecificData {  typedef struct ThreadSpecificData {
25      int debugFlag;            /* Flags whether we should output debugging      int debugFlag;            /* Flags whether we should output debugging
26                                 * information while displaying a builtin                                 * information while displaying a builtin
27                                 * dialog. */                                 * dialog. */
28      Tcl_Interp *debugInterp;  /* Interpreter to used for debugging. */      Tcl_Interp *debugInterp;  /* Interpreter to used for debugging. */
29      UINT WM_LBSELCHANGED;     /* Holds a registered windows event used for      UINT WM_LBSELCHANGED;     /* Holds a registered windows event used for
30                                 * communicating between the Directory                                 * communicating between the Directory
31                                 * Chooser dialog and its hook proc. */                                 * Chooser dialog and its hook proc. */
32  } ThreadSpecificData;  } ThreadSpecificData;
33  static Tcl_ThreadDataKey dataKey;  static Tcl_ThreadDataKey dataKey;
34    
35  /*  /*
36   * The following structures are used by Tk_MessageBoxCmd() to parse   * The following structures are used by Tk_MessageBoxCmd() to parse
37   * arguments and return results.   * arguments and return results.
38   */   */
39    
40  static const TkStateMap iconMap[] = {  static const TkStateMap iconMap[] = {
41      {MB_ICONERROR,              "error"},      {MB_ICONERROR,              "error"},
42      {MB_ICONINFORMATION,        "info"},      {MB_ICONINFORMATION,        "info"},
43      {MB_ICONQUESTION,           "question"},      {MB_ICONQUESTION,           "question"},
44      {MB_ICONWARNING,            "warning"},      {MB_ICONWARNING,            "warning"},
45      {-1,                        NULL}      {-1,                        NULL}
46  };  };
47                        
48  static const TkStateMap typeMap[] = {  static const TkStateMap typeMap[] = {
49      {MB_ABORTRETRYIGNORE,       "abortretryignore"},      {MB_ABORTRETRYIGNORE,       "abortretryignore"},
50      {MB_OK,                     "ok"},      {MB_OK,                     "ok"},
51      {MB_OKCANCEL,               "okcancel"},      {MB_OKCANCEL,               "okcancel"},
52      {MB_RETRYCANCEL,            "retrycancel"},      {MB_RETRYCANCEL,            "retrycancel"},
53      {MB_YESNO,                  "yesno"},      {MB_YESNO,                  "yesno"},
54      {MB_YESNOCANCEL,            "yesnocancel"},      {MB_YESNOCANCEL,            "yesnocancel"},
55      {-1,                        NULL}      {-1,                        NULL}
56  };  };
57    
58  static const TkStateMap buttonMap[] = {  static const TkStateMap buttonMap[] = {
59      {IDABORT,                   "abort"},      {IDABORT,                   "abort"},
60      {IDRETRY,                   "retry"},      {IDRETRY,                   "retry"},
61      {IDIGNORE,                  "ignore"},      {IDIGNORE,                  "ignore"},
62      {IDOK,                      "ok"},      {IDOK,                      "ok"},
63      {IDCANCEL,                  "cancel"},      {IDCANCEL,                  "cancel"},
64      {IDNO,                      "no"},      {IDNO,                      "no"},
65      {IDYES,                     "yes"},      {IDYES,                     "yes"},
66      {-1,                        NULL}      {-1,                        NULL}
67  };  };
68    
69  static const int buttonFlagMap[] = {  static const int buttonFlagMap[] = {
70      MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3, MB_DEFBUTTON4      MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3, MB_DEFBUTTON4
71  };  };
72    
73  static const struct {int type; int btnIds[3];} allowedTypes[] = {  static const struct {int type; int btnIds[3];} allowedTypes[] = {
74      {MB_ABORTRETRYIGNORE,       {IDABORT, IDRETRY,  IDIGNORE}},      {MB_ABORTRETRYIGNORE,       {IDABORT, IDRETRY,  IDIGNORE}},
75      {MB_OK,                     {IDOK,    -1,       -1      }},      {MB_OK,                     {IDOK,    -1,       -1      }},
76      {MB_OKCANCEL,               {IDOK,    IDCANCEL, -1      }},      {MB_OKCANCEL,               {IDOK,    IDCANCEL, -1      }},
77      {MB_RETRYCANCEL,            {IDRETRY, IDCANCEL, -1      }},      {MB_RETRYCANCEL,            {IDRETRY, IDCANCEL, -1      }},
78      {MB_YESNO,                  {IDYES,   IDNO,     -1      }},      {MB_YESNO,                  {IDYES,   IDNO,     -1      }},
79      {MB_YESNOCANCEL,            {IDYES,   IDNO,     IDCANCEL}}      {MB_YESNOCANCEL,            {IDYES,   IDNO,     IDCANCEL}}
80  };  };
81    
82  #define NUM_TYPES (sizeof(allowedTypes) / sizeof(allowedTypes[0]))  #define NUM_TYPES (sizeof(allowedTypes) / sizeof(allowedTypes[0]))
83    
84  /*  /*
85   * The following structure is used to pass information between the directory   * The following structure is used to pass information between the directory
86   * chooser procedure, Tk_ChooseDirectoryObjCmd(), and its dialog hook proc.   * chooser procedure, Tk_ChooseDirectoryObjCmd(), and its dialog hook proc.
87   */   */
88    
89  typedef struct ChooseDir {  typedef struct ChooseDir {
90      Tcl_Interp *interp;         /* Interp, used only if debug is turned on,      Tcl_Interp *interp;         /* Interp, used only if debug is turned on,
91                                   * for setting the "tk_dialog" variable. */                                   * for setting the "tk_dialog" variable. */
92      int lastCtrl;               /* Used by hook proc to keep track of last      int lastCtrl;               /* Used by hook proc to keep track of last
93                                   * control that had input focus, so when OK                                   * control that had input focus, so when OK
94                                   * is pressed we know whether to browse a                                   * is pressed we know whether to browse a
95                                   * new directory or return. */                                   * new directory or return. */
96      int lastIdx;                /* Last item that was selected in directory      int lastIdx;                /* Last item that was selected in directory
97                                   * browser listbox. */                                   * browser listbox. */
98      TCHAR path[MAX_PATH];       /* On return from choose directory dialog,      TCHAR path[MAX_PATH];       /* On return from choose directory dialog,
99                                   * holds the selected path.  Cannot return                                   * holds the selected path.  Cannot return
100                                   * selected path in ofnPtr->lpstrFile because                                   * selected path in ofnPtr->lpstrFile because
101                                   * the default dialog proc stores a '\0' in                                   * the default dialog proc stores a '\0' in
102                                   * it, since, of course, no _file_ was                                   * it, since, of course, no _file_ was
103                                   * selected. */                                   * selected. */
104  } ChooseDir;  } ChooseDir;
105    
106  /*  /*
107   * Definitions of procedures used only in this file.   * Definitions of procedures used only in this file.
108   */   */
109    
110  static UINT APIENTRY    ChooseDirectoryHookProc(HWND hdlg, UINT uMsg,  static UINT APIENTRY    ChooseDirectoryHookProc(HWND hdlg, UINT uMsg,
111                              WPARAM wParam, LPARAM lParam);                              WPARAM wParam, LPARAM lParam);
112  static UINT CALLBACK    ColorDlgHookProc(HWND hDlg, UINT uMsg, WPARAM wParam,  static UINT CALLBACK    ColorDlgHookProc(HWND hDlg, UINT uMsg, WPARAM wParam,
113                              LPARAM lParam);                              LPARAM lParam);
114  static int              GetFileNameA(ClientData clientData,  static int              GetFileNameA(ClientData clientData,
115                              Tcl_Interp *interp, int objc,                              Tcl_Interp *interp, int objc,
116                              Tcl_Obj *CONST objv[], int isOpen);                              Tcl_Obj *CONST objv[], int isOpen);
117  static int              GetFileNameW(ClientData clientData,  static int              GetFileNameW(ClientData clientData,
118                              Tcl_Interp *interp, int objc,                              Tcl_Interp *interp, int objc,
119                              Tcl_Obj *CONST objv[], int isOpen);                              Tcl_Obj *CONST objv[], int isOpen);
120  static int              MakeFilter(Tcl_Interp *interp, char *string,  static int              MakeFilter(Tcl_Interp *interp, char *string,
121                              Tcl_DString *dsPtr);                              Tcl_DString *dsPtr);
122  static UINT APIENTRY    OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam,  static UINT APIENTRY    OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam,
123                              LPARAM lParam);                              LPARAM lParam);
124  static UINT APIENTRY    OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam,  static UINT APIENTRY    OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam,
125                              LPARAM lParam);                              LPARAM lParam);
126  static void             SetTkDialog(ClientData clientData);  static void             SetTkDialog(ClientData clientData);
127  static int              TrySetDirectory(HWND hwnd, const TCHAR *dir);  static int              TrySetDirectory(HWND hwnd, const TCHAR *dir);
128    
129  /*  /*
130   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
131   *   *
132   * TkWinDialogDebug --   * TkWinDialogDebug --
133   *   *
134   *      Function to turn on/off debugging support for common dialogs under   *      Function to turn on/off debugging support for common dialogs under
135   *      windows.  The variable "tk_debug" is set to the identifier of the   *      windows.  The variable "tk_debug" is set to the identifier of the
136   *      dialog window when the modal dialog window pops up and it is safe to   *      dialog window when the modal dialog window pops up and it is safe to
137   *      send messages to the dialog.   *      send messages to the dialog.
138   *   *
139   * Results:   * Results:
140   *      None.   *      None.
141   *   *
142   * Side effects:   * Side effects:
143   *      This variable only makes sense if just one dialog is up at a time.   *      This variable only makes sense if just one dialog is up at a time.
144   *   *
145   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
146   */   */
147    
148  void              void            
149  TkWinDialogDebug(  TkWinDialogDebug(
150      int debug)      int debug)
151  {  {
152      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
153              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
154    
155      tsdPtr->debugFlag = debug;      tsdPtr->debugFlag = debug;
156  }  }
157    
158  /*  /*
159   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
160   *   *
161   * Tk_ChooseColorObjCmd --   * Tk_ChooseColorObjCmd --
162   *   *
163   *      This procedure implements the color dialog box for the Windows   *      This procedure implements the color dialog box for the Windows
164   *      platform. See the user documentation for details on what it   *      platform. See the user documentation for details on what it
165   *      does.   *      does.
166   *   *
167   * Results:   * Results:
168   *      See user documentation.   *      See user documentation.
169   *   *
170   * Side effects:   * Side effects:
171   *      A dialog window is created the first time this procedure is called.   *      A dialog window is created the first time this procedure is called.
172   *      This window is not destroyed and will be reused the next time the   *      This window is not destroyed and will be reused the next time the
173   *      application invokes the "tk_chooseColor" command.   *      application invokes the "tk_chooseColor" command.
174   *   *
175   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
176   */   */
177    
178  int  int
179  Tk_ChooseColorObjCmd(clientData, interp, objc, objv)  Tk_ChooseColorObjCmd(clientData, interp, objc, objv)
180      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
181      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
182      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
183      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
184  {  {
185      Tk_Window tkwin, parent;      Tk_Window tkwin, parent;
186      HWND hWnd;      HWND hWnd;
187      int i, oldMode, winCode;      int i, oldMode, winCode;
188      CHOOSECOLOR chooseColor;      CHOOSECOLOR chooseColor;
189      static inited = 0;      static inited = 0;
190      static COLORREF dwCustColors[16];      static COLORREF dwCustColors[16];
191      static long oldColor;               /* the color selected last time */      static long oldColor;               /* the color selected last time */
192      static char *optionStrings[] = {      static char *optionStrings[] = {
193          "-initialcolor",    "-parent",      "-title",       NULL          "-initialcolor",    "-parent",      "-title",       NULL
194      };      };
195      enum options {      enum options {
196          COLOR_INITIAL,      COLOR_PARENT,   COLOR_TITLE          COLOR_INITIAL,      COLOR_PARENT,   COLOR_TITLE
197      };      };
198    
199      if (inited == 0) {      if (inited == 0) {
200          /*          /*
201           * dwCustColors stores the custom color which the user can           * dwCustColors stores the custom color which the user can
202           * modify. We store these colors in a static array so that the next           * modify. We store these colors in a static array so that the next
203           * time the color dialog pops up, the same set of custom colors           * time the color dialog pops up, the same set of custom colors
204           * remain in the dialog.           * remain in the dialog.
205           */           */
206          for (i = 0; i < 16; i++) {          for (i = 0; i < 16; i++) {
207              dwCustColors[i] = RGB(255-i * 10, i, i * 10);              dwCustColors[i] = RGB(255-i * 10, i, i * 10);
208          }          }
209          oldColor = RGB(0xa0, 0xa0, 0xa0);          oldColor = RGB(0xa0, 0xa0, 0xa0);
210          inited = 1;          inited = 1;
211      }      }
212    
213      tkwin = (Tk_Window) clientData;      tkwin = (Tk_Window) clientData;
214    
215      parent                      = tkwin;      parent                      = tkwin;
216      chooseColor.lStructSize     = sizeof(CHOOSECOLOR);      chooseColor.lStructSize     = sizeof(CHOOSECOLOR);
217      chooseColor.hwndOwner       = NULL;                      chooseColor.hwndOwner       = NULL;                
218      chooseColor.hInstance       = NULL;      chooseColor.hInstance       = NULL;
219      chooseColor.rgbResult       = oldColor;      chooseColor.rgbResult       = oldColor;
220      chooseColor.lpCustColors    = dwCustColors;      chooseColor.lpCustColors    = dwCustColors;
221      chooseColor.Flags           = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK;      chooseColor.Flags           = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK;
222      chooseColor.lCustData       = (LPARAM) NULL;      chooseColor.lCustData       = (LPARAM) NULL;
223      chooseColor.lpfnHook        = ColorDlgHookProc;      chooseColor.lpfnHook        = ColorDlgHookProc;
224      chooseColor.lpTemplateName  = (LPTSTR) interp;      chooseColor.lpTemplateName  = (LPTSTR) interp;
225    
226      for (i = 1; i < objc; i += 2) {      for (i = 1; i < objc; i += 2) {
227          int index;          int index;
228          char *string;          char *string;
229          Tcl_Obj *optionPtr, *valuePtr;          Tcl_Obj *optionPtr, *valuePtr;
230    
231          optionPtr = objv[i];          optionPtr = objv[i];
232          valuePtr = objv[i + 1];          valuePtr = objv[i + 1];
233    
234          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",
235                  TCL_EXACT, &index) != TCL_OK) {                  TCL_EXACT, &index) != TCL_OK) {
236              return TCL_ERROR;              return TCL_ERROR;
237          }          }
238          if (i + 1 == objc) {          if (i + 1 == objc) {
239              string = Tcl_GetStringFromObj(optionPtr, NULL);              string = Tcl_GetStringFromObj(optionPtr, NULL);
240              Tcl_AppendResult(interp, "value for \"", string, "\" missing",              Tcl_AppendResult(interp, "value for \"", string, "\" missing",
241                      (char *) NULL);                      (char *) NULL);
242              return TCL_ERROR;              return TCL_ERROR;
243          }          }
244    
245          string = Tcl_GetStringFromObj(valuePtr, NULL);          string = Tcl_GetStringFromObj(valuePtr, NULL);
246          switch ((enum options) index) {          switch ((enum options) index) {
247              case COLOR_INITIAL: {              case COLOR_INITIAL: {
248                  XColor *colorPtr;                  XColor *colorPtr;
249    
250                  colorPtr = Tk_GetColor(interp, tkwin, string);                  colorPtr = Tk_GetColor(interp, tkwin, string);
251                  if (colorPtr == NULL) {                  if (colorPtr == NULL) {
252                      return TCL_ERROR;                      return TCL_ERROR;
253                  }                  }
254                  chooseColor.rgbResult = RGB(colorPtr->red / 0x100,                  chooseColor.rgbResult = RGB(colorPtr->red / 0x100,
255                          colorPtr->green / 0x100, colorPtr->blue / 0x100);                          colorPtr->green / 0x100, colorPtr->blue / 0x100);
256                  break;                  break;
257              }              }
258              case COLOR_PARENT: {              case COLOR_PARENT: {
259                  parent = Tk_NameToWindow(interp, string, tkwin);                  parent = Tk_NameToWindow(interp, string, tkwin);
260                  if (parent == NULL) {                  if (parent == NULL) {
261                      return TCL_ERROR;                      return TCL_ERROR;
262                  }                  }
263                  break;                  break;
264              }              }
265              case COLOR_TITLE: {              case COLOR_TITLE: {
266                  chooseColor.lCustData = (LPARAM) string;                  chooseColor.lCustData = (LPARAM) string;
267                  break;                  break;
268              }              }
269          }          }
270      }      }
271    
272      Tk_MakeWindowExist(parent);      Tk_MakeWindowExist(parent);
273      chooseColor.hwndOwner = NULL;      chooseColor.hwndOwner = NULL;
274      hWnd = Tk_GetHWND(Tk_WindowId(parent));      hWnd = Tk_GetHWND(Tk_WindowId(parent));
275      chooseColor.hwndOwner = hWnd;      chooseColor.hwndOwner = hWnd;
276            
277      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
278      winCode = ChooseColor(&chooseColor);      winCode = ChooseColor(&chooseColor);
279      (void) Tcl_SetServiceMode(oldMode);      (void) Tcl_SetServiceMode(oldMode);
280    
281      /*      /*
282       * Ensure that hWnd is enabled, because it can happen that we       * Ensure that hWnd is enabled, because it can happen that we
283       * have updated the wrapper of the parent, which causes us to       * have updated the wrapper of the parent, which causes us to
284       * leave this child disabled (Windows loses sync).       * leave this child disabled (Windows loses sync).
285       */       */
286      EnableWindow(hWnd, 1);      EnableWindow(hWnd, 1);
287    
288      /*      /*
289       * Clear the interp result since anything may have happened during the       * Clear the interp result since anything may have happened during the
290       * modal loop.       * modal loop.
291       */       */
292    
293      Tcl_ResetResult(interp);      Tcl_ResetResult(interp);
294    
295      /*      /*
296       * 3. Process the result of the dialog       * 3. Process the result of the dialog
297       */       */
298    
299      if (winCode) {      if (winCode) {
300          /*          /*
301           * User has selected a color           * User has selected a color
302           */           */
303          char result[100];          char result[100];
304    
305          sprintf(result, "#%02x%02x%02x",          sprintf(result, "#%02x%02x%02x",
306          GetRValue(chooseColor.rgbResult),          GetRValue(chooseColor.rgbResult),
307                  GetGValue(chooseColor.rgbResult),                  GetGValue(chooseColor.rgbResult),
308                  GetBValue(chooseColor.rgbResult));                  GetBValue(chooseColor.rgbResult));
309          Tcl_AppendResult(interp, result, NULL);          Tcl_AppendResult(interp, result, NULL);
310          oldColor = chooseColor.rgbResult;          oldColor = chooseColor.rgbResult;
311      }      }
312      return TCL_OK;      return TCL_OK;
313  }  }
314    
315  /*  /*
316   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
317   *   *
318   * ColorDlgHookProc --   * ColorDlgHookProc --
319   *   *
320   *      Provides special handling of messages for the Color common dialog   *      Provides special handling of messages for the Color common dialog
321   *      box.  Used to set the title when the dialog first appears.   *      box.  Used to set the title when the dialog first appears.
322   *   *
323   * Results:   * Results:
324   *      The return value is 0 if the default dialog box procedure should   *      The return value is 0 if the default dialog box procedure should
325   *      handle the message, non-zero otherwise.   *      handle the message, non-zero otherwise.
326   *   *
327   * Side effects:   * Side effects:
328   *      Changes the title of the dialog window.   *      Changes the title of the dialog window.
329   *   *
330   *----------------------------------------------------------------------   *----------------------------------------------------------------------
331   */   */
332    
333  static UINT CALLBACK  static UINT CALLBACK
334  ColorDlgHookProc(hDlg, uMsg, wParam, lParam)  ColorDlgHookProc(hDlg, uMsg, wParam, lParam)
335      HWND hDlg;                  /* Handle to the color dialog. */      HWND hDlg;                  /* Handle to the color dialog. */
336      UINT uMsg;                  /* Type of message. */      UINT uMsg;                  /* Type of message. */
337      WPARAM wParam;              /* First message parameter. */      WPARAM wParam;              /* First message parameter. */
338      LPARAM lParam;              /* Second message parameter. */      LPARAM lParam;              /* Second message parameter. */
339  {  {
340      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
341              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
342    
343      switch (uMsg) {      switch (uMsg) {
344          case WM_INITDIALOG: {          case WM_INITDIALOG: {
345              const char *title;              const char *title;
346              CHOOSECOLOR *ccPtr;              CHOOSECOLOR *ccPtr;
347              Tcl_DString ds;              Tcl_DString ds;
348    
349              /*              /*
350               * Set the title string of the dialog.               * Set the title string of the dialog.
351               */               */
352    
353              ccPtr = (CHOOSECOLOR *) lParam;              ccPtr = (CHOOSECOLOR *) lParam;
354              title = (const char *) ccPtr->lCustData;              title = (const char *) ccPtr->lCustData;
355              if ((title != NULL) && (title[0] != '\0')) {              if ((title != NULL) && (title[0] != '\0')) {
356                  Tcl_UtfToExternalDString(NULL, title, -1, &ds);                  Tcl_UtfToExternalDString(NULL, title, -1, &ds);
357                  SetWindowText(hDlg, (TCHAR *) Tcl_DStringValue(&ds));                  SetWindowText(hDlg, (TCHAR *) Tcl_DStringValue(&ds));
358                  Tcl_DStringFree(&ds);                  Tcl_DStringFree(&ds);
359              }              }
360              if (tsdPtr->debugFlag) {              if (tsdPtr->debugFlag) {
361                  tsdPtr->debugInterp = (Tcl_Interp *) ccPtr->lpTemplateName;                  tsdPtr->debugInterp = (Tcl_Interp *) ccPtr->lpTemplateName;
362                  Tcl_DoWhenIdle(SetTkDialog, (ClientData) hDlg);                  Tcl_DoWhenIdle(SetTkDialog, (ClientData) hDlg);
363              }              }
364              return TRUE;              return TRUE;
365          }          }
366      }      }
367      return FALSE;      return FALSE;
368  }  }
369    
370  /*  /*
371   *----------------------------------------------------------------------   *----------------------------------------------------------------------
372   *   *
373   * Tk_GetOpenFileCmd --   * Tk_GetOpenFileCmd --
374   *   *
375   *      This procedure implements the "open file" dialog box for the   *      This procedure implements the "open file" dialog box for the
376   *      Windows platform. See the user documentation for details on what   *      Windows platform. See the user documentation for details on what
377   *      it does.   *      it does.
378   *   *
379   * Results:   * Results:
380   *      See user documentation.   *      See user documentation.
381   *   *
382   * Side effects:   * Side effects:
383   *      A dialog window is created the first this procedure is called.   *      A dialog window is created the first this procedure is called.
384   *   *
385   *----------------------------------------------------------------------   *----------------------------------------------------------------------
386   */   */
387    
388  int  int
389  Tk_GetOpenFileObjCmd(clientData, interp, objc, objv)  Tk_GetOpenFileObjCmd(clientData, interp, objc, objv)
390      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
391      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
392      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
393      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
394  {  {
395      if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {      if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
396          return GetFileNameW(clientData, interp, objc, objv, 1);          return GetFileNameW(clientData, interp, objc, objv, 1);
397      } else {      } else {
398          return GetFileNameA(clientData, interp, objc, objv, 1);          return GetFileNameA(clientData, interp, objc, objv, 1);
399      }      }
400  }  }
401    
402  /*  /*
403   *----------------------------------------------------------------------   *----------------------------------------------------------------------
404   *   *
405   * Tk_GetSaveFileCmd --   * Tk_GetSaveFileCmd --
406   *   *
407   *      Same as Tk_GetOpenFileCmd but opens a "save file" dialog box   *      Same as Tk_GetOpenFileCmd but opens a "save file" dialog box
408   *      instead   *      instead
409   *   *
410   * Results:   * Results:
411   *      Same as Tk_GetOpenFileCmd.   *      Same as Tk_GetOpenFileCmd.
412   *   *
413   * Side effects:   * Side effects:
414   *      Same as Tk_GetOpenFileCmd.   *      Same as Tk_GetOpenFileCmd.
415   *   *
416   *----------------------------------------------------------------------   *----------------------------------------------------------------------
417   */   */
418    
419  int  int
420  Tk_GetSaveFileObjCmd(clientData, interp, objc, objv)  Tk_GetSaveFileObjCmd(clientData, interp, objc, objv)
421      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
422      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
423      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
424      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
425  {  {
426      if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {      if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
427          return GetFileNameW(clientData, interp, objc, objv, 0);          return GetFileNameW(clientData, interp, objc, objv, 0);
428      } else {      } else {
429          return GetFileNameA(clientData, interp, objc, objv, 0);          return GetFileNameA(clientData, interp, objc, objv, 0);
430      }      }
431  }  }
432    
433  /*  /*
434   *----------------------------------------------------------------------   *----------------------------------------------------------------------
435   *   *
436   * GetFileNameW --   * GetFileNameW --
437   *   *
438   *      Calls GetOpenFileName() or GetSaveFileName().   *      Calls GetOpenFileName() or GetSaveFileName().
439   *   *
440   * Results:   * Results:
441   *      See user documentation.   *      See user documentation.
442   *   *
443   * Side effects:   * Side effects:
444   *      See user documentation.   *      See user documentation.
445   *   *
446   *----------------------------------------------------------------------   *----------------------------------------------------------------------
447   */   */
448    
449  static int  static int
450  GetFileNameW(clientData, interp, objc, objv, open)  GetFileNameW(clientData, interp, objc, objv, open)
451      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
452      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
453      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
454      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
455      int open;                   /* 1 to call GetOpenFileName(), 0 to      int open;                   /* 1 to call GetOpenFileName(), 0 to
456                                   * call GetSaveFileName(). */                                   * call GetSaveFileName(). */
457  {  {
458      Tcl_Encoding unicodeEncoding = Tcl_GetEncoding(NULL, "unicode");      Tcl_Encoding unicodeEncoding = Tcl_GetEncoding(NULL, "unicode");
459      OPENFILENAMEW ofn;      OPENFILENAMEW ofn;
460      WCHAR file[MAX_PATH];      WCHAR file[MAX_PATH];
461      int result, winCode, oldMode, i;      int result, winCode, oldMode, i;
462      char *extension, *filter, *title;      char *extension, *filter, *title;
463      Tk_Window tkwin;      Tk_Window tkwin;
464      HWND hWnd;      HWND hWnd;
465      Tcl_DString utfFilterString, utfDirString;      Tcl_DString utfFilterString, utfDirString;
466      Tcl_DString extString, filterString, dirString, titleString;      Tcl_DString extString, filterString, dirString, titleString;
467      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
468              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
469      static char *optionStrings[] = {      static char *optionStrings[] = {
470          "-defaultextension", "-filetypes", "-initialdir", "-initialfile",          "-defaultextension", "-filetypes", "-initialdir", "-initialfile",
471          "-parent",      "-title",       NULL          "-parent",      "-title",       NULL
472      };      };
473      enum options {      enum options {
474          FILE_DEFAULT,   FILE_TYPES,     FILE_INITDIR,   FILE_INITFILE,          FILE_DEFAULT,   FILE_TYPES,     FILE_INITDIR,   FILE_INITFILE,
475          FILE_PARENT,    FILE_TITLE          FILE_PARENT,    FILE_TITLE
476      };      };
477    
478      result = TCL_ERROR;      result = TCL_ERROR;
479      file[0] = '\0';      file[0] = '\0';
480    
481      /*      /*
482       * Parse the arguments.       * Parse the arguments.
483       */       */
484    
485      extension = NULL;      extension = NULL;
486      filter = NULL;      filter = NULL;
487      Tcl_DStringInit(&utfFilterString);      Tcl_DStringInit(&utfFilterString);
488      Tcl_DStringInit(&utfDirString);      Tcl_DStringInit(&utfDirString);
489      tkwin = (Tk_Window) clientData;      tkwin = (Tk_Window) clientData;
490      title = NULL;      title = NULL;
491    
492      for (i = 1; i < objc; i += 2) {      for (i = 1; i < objc; i += 2) {
493          int index;          int index;
494          char *string;          char *string;
495          Tcl_Obj *optionPtr, *valuePtr;          Tcl_Obj *optionPtr, *valuePtr;
496    
497          optionPtr = objv[i];          optionPtr = objv[i];
498          valuePtr = objv[i + 1];          valuePtr = objv[i + 1];
499    
500          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",
501                  0, &index) != TCL_OK) {                  0, &index) != TCL_OK) {
502              goto end;              goto end;
503          }          }
504          if (i + 1 == objc) {          if (i + 1 == objc) {
505              string = Tcl_GetStringFromObj(optionPtr, NULL);              string = Tcl_GetStringFromObj(optionPtr, NULL);
506              Tcl_AppendResult(interp, "value for \"", string, "\" missing",              Tcl_AppendResult(interp, "value for \"", string, "\" missing",
507                      (char *) NULL);                      (char *) NULL);
508              goto end;              goto end;
509          }          }
510    
511          string = Tcl_GetStringFromObj(valuePtr, NULL);          string = Tcl_GetStringFromObj(valuePtr, NULL);
512          switch ((enum options) index) {          switch ((enum options) index) {
513              case FILE_DEFAULT: {              case FILE_DEFAULT: {
514                  if (string[0] == '.') {                  if (string[0] == '.') {
515                      string++;                      string++;
516                  }                  }
517                  extension = string;                  extension = string;
518                  break;                  break;
519              }              }
520              case FILE_TYPES: {              case FILE_TYPES: {
521                  Tcl_DStringFree(&utfFilterString);                  Tcl_DStringFree(&utfFilterString);
522                  if (MakeFilter(interp, string, &utfFilterString) != TCL_OK) {                  if (MakeFilter(interp, string, &utfFilterString) != TCL_OK) {
523                      goto end;                      goto end;
524                  }                  }
525                  filter = Tcl_DStringValue(&utfFilterString);                  filter = Tcl_DStringValue(&utfFilterString);
526                  break;                  break;
527              }              }
528              case FILE_INITDIR: {              case FILE_INITDIR: {
529                  Tcl_DStringFree(&utfDirString);                  Tcl_DStringFree(&utfDirString);
530                  if (Tcl_TranslateFileName(interp, string,                  if (Tcl_TranslateFileName(interp, string,
531                          &utfDirString) == NULL) {                          &utfDirString) == NULL) {
532                      goto end;                      goto end;
533                  }                  }
534                  break;                  break;
535              }              }
536              case FILE_INITFILE: {              case FILE_INITFILE: {
537                  Tcl_DString ds;                  Tcl_DString ds;
538    
539                  if (Tcl_TranslateFileName(interp, string, &ds) == NULL) {                  if (Tcl_TranslateFileName(interp, string, &ds) == NULL) {
540                      goto end;                      goto end;
541                  }                  }
542                  Tcl_UtfToExternal(NULL, unicodeEncoding, Tcl_DStringValue(&ds),                  Tcl_UtfToExternal(NULL, unicodeEncoding, Tcl_DStringValue(&ds),
543                          Tcl_DStringLength(&ds), 0, NULL, (char *) file,                          Tcl_DStringLength(&ds), 0, NULL, (char *) file,
544                          sizeof(file), NULL, NULL, NULL);                          sizeof(file), NULL, NULL, NULL);
545                  break;                  break;
546              }              }
547              case FILE_PARENT: {              case FILE_PARENT: {
548                  tkwin = Tk_NameToWindow(interp, string, tkwin);                  tkwin = Tk_NameToWindow(interp, string, tkwin);
549                  if (tkwin == NULL) {                  if (tkwin == NULL) {
550                      goto end;                      goto end;
551                  }                  }
552                  break;                  break;
553              }              }
554              case FILE_TITLE: {              case FILE_TITLE: {
555                  title = string;                  title = string;
556                  break;                  break;
557              }              }
558          }          }
559      }      }
560    
561      if (filter == NULL) {      if (filter == NULL) {
562          if (MakeFilter(interp, "", &utfFilterString) != TCL_OK) {          if (MakeFilter(interp, "", &utfFilterString) != TCL_OK) {
563              goto end;              goto end;
564          }          }
565      }      }
566    
567      Tk_MakeWindowExist(tkwin);      Tk_MakeWindowExist(tkwin);
568      hWnd = Tk_GetHWND(Tk_WindowId(tkwin));      hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
569    
570      ofn.lStructSize             = sizeof(ofn);      ofn.lStructSize             = sizeof(ofn);
571      ofn.hwndOwner               = hWnd;      ofn.hwndOwner               = hWnd;
572      ofn.hInstance               = (HINSTANCE) GetWindowLong(ofn.hwndOwner,      ofn.hInstance               = (HINSTANCE) GetWindowLong(ofn.hwndOwner,
573                                          GWL_HINSTANCE);                                          GWL_HINSTANCE);
574      ofn.lpstrFilter             = NULL;      ofn.lpstrFilter             = NULL;
575      ofn.lpstrCustomFilter       = NULL;      ofn.lpstrCustomFilter       = NULL;
576      ofn.nMaxCustFilter          = 0;      ofn.nMaxCustFilter          = 0;
577      ofn.nFilterIndex            = 0;      ofn.nFilterIndex            = 0;
578      ofn.lpstrFile               = (WCHAR *) file;      ofn.lpstrFile               = (WCHAR *) file;
579      ofn.nMaxFile                = MAX_PATH;      ofn.nMaxFile                = MAX_PATH;
580      ofn.lpstrFileTitle          = NULL;      ofn.lpstrFileTitle          = NULL;
581      ofn.nMaxFileTitle           = 0;      ofn.nMaxFileTitle           = 0;
582      ofn.lpstrInitialDir         = NULL;      ofn.lpstrInitialDir         = NULL;
583      ofn.lpstrTitle              = NULL;      ofn.lpstrTitle              = NULL;
584      ofn.Flags                   = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST      ofn.Flags                   = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST
585                                    | OFN_NOCHANGEDIR | OFN_EXPLORER;                                    | OFN_NOCHANGEDIR | OFN_EXPLORER;
586      ofn.nFileOffset             = 0;      ofn.nFileOffset             = 0;
587      ofn.nFileExtension          = 0;      ofn.nFileExtension          = 0;
588      ofn.lpstrDefExt             = NULL;      ofn.lpstrDefExt             = NULL;
589      ofn.lpfnHook                = OFNHookProcW;      ofn.lpfnHook                = OFNHookProcW;
590      ofn.lCustData               = (LPARAM) interp;      ofn.lCustData               = (LPARAM) interp;
591      ofn.lpTemplateName          = NULL;      ofn.lpTemplateName          = NULL;
592    
593      if (open != 0) {      if (open != 0) {
594          ofn.Flags |= OFN_FILEMUSTEXIST;          ofn.Flags |= OFN_FILEMUSTEXIST;
595      } else {      } else {
596          ofn.Flags |= OFN_OVERWRITEPROMPT;          ofn.Flags |= OFN_OVERWRITEPROMPT;
597      }      }
598    
599      if (tsdPtr->debugFlag != 0) {      if (tsdPtr->debugFlag != 0) {
600          ofn.Flags |= OFN_ENABLEHOOK;          ofn.Flags |= OFN_ENABLEHOOK;
601      }      }
602    
603      if (extension != NULL) {      if (extension != NULL) {
604          Tcl_UtfToExternalDString(unicodeEncoding, extension, -1, &extString);          Tcl_UtfToExternalDString(unicodeEncoding, extension, -1, &extString);
605          ofn.lpstrDefExt = (WCHAR *) Tcl_DStringValue(&extString);          ofn.lpstrDefExt = (WCHAR *) Tcl_DStringValue(&extString);
606      }      }
607    
608      Tcl_UtfToExternalDString(unicodeEncoding, Tcl_DStringValue(&utfFilterString),      Tcl_UtfToExternalDString(unicodeEncoding, Tcl_DStringValue(&utfFilterString),
609              Tcl_DStringLength(&utfFilterString), &filterString);              Tcl_DStringLength(&utfFilterString), &filterString);
610      ofn.lpstrFilter = (WCHAR *) Tcl_DStringValue(&filterString);      ofn.lpstrFilter = (WCHAR *) Tcl_DStringValue(&filterString);
611    
612      if (Tcl_DStringValue(&utfDirString)[0] != '\0') {      if (Tcl_DStringValue(&utfDirString)[0] != '\0') {
613          Tcl_UtfToExternalDString(unicodeEncoding, Tcl_DStringValue(&utfDirString),          Tcl_UtfToExternalDString(unicodeEncoding, Tcl_DStringValue(&utfDirString),
614                  Tcl_DStringLength(&utfDirString), &dirString);                  Tcl_DStringLength(&utfDirString), &dirString);
615          ofn.lpstrInitialDir = (WCHAR *) Tcl_DStringValue(&dirString);          ofn.lpstrInitialDir = (WCHAR *) Tcl_DStringValue(&dirString);
616      }      }
617    
618      if (title != NULL) {      if (title != NULL) {
619          Tcl_UtfToExternalDString(unicodeEncoding, title, -1, &titleString);          Tcl_UtfToExternalDString(unicodeEncoding, title, -1, &titleString);
620          ofn.lpstrTitle = (WCHAR *) Tcl_DStringValue(&titleString);          ofn.lpstrTitle = (WCHAR *) Tcl_DStringValue(&titleString);
621      }      }
622    
623      /*      /*
624       * Popup the dialog.       * Popup the dialog.
625       */       */
626    
627      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
628      if (open != 0) {      if (open != 0) {
629          winCode = GetOpenFileNameW(&ofn);          winCode = GetOpenFileNameW(&ofn);
630      } else {      } else {
631          winCode = GetSaveFileNameW(&ofn);          winCode = GetSaveFileNameW(&ofn);
632      }      }
633      Tcl_SetServiceMode(oldMode);      Tcl_SetServiceMode(oldMode);
634    
635      /*      /*
636       * Ensure that hWnd is enabled, because it can happen that we       * Ensure that hWnd is enabled, because it can happen that we
637       * have updated the wrapper of the parent, which causes us to       * have updated the wrapper of the parent, which causes us to
638       * leave this child disabled (Windows loses sync).       * leave this child disabled (Windows loses sync).
639       */       */
640      EnableWindow(hWnd, 1);      EnableWindow(hWnd, 1);
641    
642      /*      /*
643       * Clear the interp result since anything may have happened during the       * Clear the interp result since anything may have happened during the
644       * modal loop.       * modal loop.
645       */       */
646    
647      Tcl_ResetResult(interp);      Tcl_ResetResult(interp);
648    
649      /*      /*
650       * Process the results.       * Process the results.
651       */       */
652    
653      if (winCode != 0) {      if (winCode != 0) {
654          char *p;          char *p;
655          Tcl_DString ds;          Tcl_DString ds;
656    
657          Tcl_ExternalToUtfDString(unicodeEncoding, (char *) ofn.lpstrFile, -1, &ds);          Tcl_ExternalToUtfDString(unicodeEncoding, (char *) ofn.lpstrFile, -1, &ds);
658          for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) {          for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) {
659              /*              /*
660               * Change the pathname to the Tcl "normalized" pathname, where               * Change the pathname to the Tcl "normalized" pathname, where
661               * back slashes are used instead of forward slashes               * back slashes are used instead of forward slashes
662               */               */
663              if (*p == '\\') {              if (*p == '\\') {
664                  *p = '/';                  *p = '/';
665              }              }
666          }          }
667          Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);          Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);
668          Tcl_DStringFree(&ds);          Tcl_DStringFree(&ds);
669      }      }
670    
671      if (ofn.lpstrTitle != NULL) {      if (ofn.lpstrTitle != NULL) {
672          Tcl_DStringFree(&titleString);          Tcl_DStringFree(&titleString);
673      }      }
674      if (ofn.lpstrInitialDir != NULL) {      if (ofn.lpstrInitialDir != NULL) {
675          Tcl_DStringFree(&dirString);          Tcl_DStringFree(&dirString);
676      }      }
677      Tcl_DStringFree(&filterString);      Tcl_DStringFree(&filterString);
678      if (ofn.lpstrDefExt != NULL) {      if (ofn.lpstrDefExt != NULL) {
679          Tcl_DStringFree(&extString);          Tcl_DStringFree(&extString);
680      }      }
681      result = TCL_OK;      result = TCL_OK;
682    
683      end:      end:
684      Tcl_DStringFree(&utfDirString);      Tcl_DStringFree(&utfDirString);
685      Tcl_DStringFree(&utfFilterString);      Tcl_DStringFree(&utfFilterString);
686    
687      return result;      return result;
688  }  }
689    
690  /*  /*
691   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
692   *   *
693   * OFNHookProcW --   * OFNHookProcW --
694   *   *
695   *      Hook procedure called only if debugging is turned on.  Sets   *      Hook procedure called only if debugging is turned on.  Sets
696   *      the "tk_dialog" variable when the dialog is ready to receive   *      the "tk_dialog" variable when the dialog is ready to receive
697   *      messages.   *      messages.
698   *   *
699   * Results:   * Results:
700   *      Returns 0 to allow default processing of messages to occur.   *      Returns 0 to allow default processing of messages to occur.
701   *   *
702   * Side effects:   * Side effects:
703   *      None.   *      None.
704   *   *
705   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
706   */   */
707    
708  static UINT APIENTRY  static UINT APIENTRY
709  OFNHookProcW(  OFNHookProcW(
710      HWND hdlg,          // handle to child dialog window      HWND hdlg,          // handle to child dialog window
711      UINT uMsg,          // message identifier      UINT uMsg,          // message identifier
712      WPARAM wParam,      // message parameter      WPARAM wParam,      // message parameter
713      LPARAM lParam)      // message parameter      LPARAM lParam)      // message parameter
714  {  {
715      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
716              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
717      OPENFILENAMEW *ofnPtr;      OPENFILENAMEW *ofnPtr;
718    
719      if (uMsg == WM_INITDIALOG) {      if (uMsg == WM_INITDIALOG) {
720          SetWindowLong(hdlg, GWL_USERDATA, lParam);          SetWindowLong(hdlg, GWL_USERDATA, lParam);
721      } else if (uMsg == WM_WINDOWPOSCHANGED) {      } else if (uMsg == WM_WINDOWPOSCHANGED) {
722          /*          /*
723           * This message is delivered at the right time to enable Tk           * This message is delivered at the right time to enable Tk
724           * to set the debug information.  Unhooks itself so it           * to set the debug information.  Unhooks itself so it
725           * won't set the debug information every time it gets a           * won't set the debug information every time it gets a
726           * WM_WINDOWPOSCHANGED message.           * WM_WINDOWPOSCHANGED message.
727           */           */
728    
729          ofnPtr = (OPENFILENAMEW *) GetWindowLong(hdlg, GWL_USERDATA);          ofnPtr = (OPENFILENAMEW *) GetWindowLong(hdlg, GWL_USERDATA);
730          if (ofnPtr != NULL) {          if (ofnPtr != NULL) {
731              hdlg = GetParent(hdlg);              hdlg = GetParent(hdlg);
732              tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData;              tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData;
733              Tcl_DoWhenIdle(SetTkDialog, (ClientData) hdlg);              Tcl_DoWhenIdle(SetTkDialog, (ClientData) hdlg);
734              SetWindowLong(hdlg, GWL_USERDATA, (LPARAM) NULL);              SetWindowLong(hdlg, GWL_USERDATA, (LPARAM) NULL);
735          }          }
736      }      }
737      return 0;      return 0;
738  }  }
739    
740  /*  /*
741   *----------------------------------------------------------------------   *----------------------------------------------------------------------
742   *   *
743   * GetFileNameA --   * GetFileNameA --
744   *   *
745   *      Calls GetOpenFileName() or GetSaveFileName().   *      Calls GetOpenFileName() or GetSaveFileName().
746   *   *
747   * Results:   * Results:
748   *      See user documentation.   *      See user documentation.
749   *   *
750   * Side effects:   * Side effects:
751   *      See user documentation.   *      See user documentation.
752   *   *
753   *----------------------------------------------------------------------   *----------------------------------------------------------------------
754   */   */
755    
756  static int  static int
757  GetFileNameA(clientData, interp, objc, objv, open)  GetFileNameA(clientData, interp, objc, objv, open)
758      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
759      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
760      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
761      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
762      int open;                   /* 1 to call GetOpenFileName(), 0 to      int open;                   /* 1 to call GetOpenFileName(), 0 to
763                                   * call GetSaveFileName(). */                                   * call GetSaveFileName(). */
764  {  {
765      OPENFILENAME ofn;      OPENFILENAME ofn;
766      TCHAR file[MAX_PATH], savePath[MAX_PATH];      TCHAR file[MAX_PATH], savePath[MAX_PATH];
767      int result, winCode, oldMode, i;      int result, winCode, oldMode, i;
768      char *extension, *filter, *title;      char *extension, *filter, *title;
769      Tk_Window tkwin;      Tk_Window tkwin;
770      HWND hWnd;      HWND hWnd;
771      Tcl_DString utfFilterString, utfDirString;      Tcl_DString utfFilterString, utfDirString;
772      Tcl_DString extString, filterString, dirString, titleString;      Tcl_DString extString, filterString, dirString, titleString;
773      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
774              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
775      static char *optionStrings[] = {      static char *optionStrings[] = {
776          "-defaultextension", "-filetypes", "-initialdir", "-initialfile",          "-defaultextension", "-filetypes", "-initialdir", "-initialfile",
777          "-parent",      "-title",       NULL          "-parent",      "-title",       NULL
778      };      };
779      enum options {      enum options {
780          FILE_DEFAULT,   FILE_TYPES,     FILE_INITDIR,   FILE_INITFILE,          FILE_DEFAULT,   FILE_TYPES,     FILE_INITDIR,   FILE_INITFILE,
781          FILE_PARENT,    FILE_TITLE          FILE_PARENT,    FILE_TITLE
782      };      };
783    
784      result = TCL_ERROR;      result = TCL_ERROR;
785      file[0] = '\0';      file[0] = '\0';
786    
787      /*      /*
788       * Parse the arguments.       * Parse the arguments.
789       */       */
790    
791      extension = NULL;      extension = NULL;
792      filter = NULL;      filter = NULL;
793      Tcl_DStringInit(&utfFilterString);      Tcl_DStringInit(&utfFilterString);
794      Tcl_DStringInit(&utfDirString);      Tcl_DStringInit(&utfDirString);
795      tkwin = (Tk_Window) clientData;      tkwin = (Tk_Window) clientData;
796      title = NULL;      title = NULL;
797    
798      for (i = 1; i < objc; i += 2) {      for (i = 1; i < objc; i += 2) {
799          int index;          int index;
800          char *string;          char *string;
801          Tcl_Obj *optionPtr, *valuePtr;          Tcl_Obj *optionPtr, *valuePtr;
802    
803          optionPtr = objv[i];          optionPtr = objv[i];
804          valuePtr = objv[i + 1];          valuePtr = objv[i + 1];
805    
806          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",
807                  0, &index) != TCL_OK) {                  0, &index) != TCL_OK) {
808              goto end;              goto end;
809          }          }
810          if (i + 1 == objc) {          if (i + 1 == objc) {
811              string = Tcl_GetStringFromObj(optionPtr, NULL);              string = Tcl_GetStringFromObj(optionPtr, NULL);
812              Tcl_AppendResult(interp, "value for \"", string, "\" missing",              Tcl_AppendResult(interp, "value for \"", string, "\" missing",
813                      (char *) NULL);                      (char *) NULL);
814              goto end;              goto end;
815          }          }
816    
817          string = Tcl_GetStringFromObj(valuePtr, NULL);          string = Tcl_GetStringFromObj(valuePtr, NULL);
818          switch ((enum options) index) {          switch ((enum options) index) {
819              case FILE_DEFAULT: {              case FILE_DEFAULT: {
820                  if (string[0] == '.') {                  if (string[0] == '.') {
821                      string++;                      string++;
822                  }                  }
823                  extension = string;                  extension = string;
824                  break;                  break;
825              }              }
826              case FILE_TYPES: {              case FILE_TYPES: {
827                  Tcl_DStringFree(&utfFilterString);                  Tcl_DStringFree(&utfFilterString);
828                  if (MakeFilter(interp, string, &utfFilterString) != TCL_OK) {                  if (MakeFilter(interp, string, &utfFilterString) != TCL_OK) {
829                      goto end;                      goto end;
830                  }                  }
831                  filter = Tcl_DStringValue(&utfFilterString);                  filter = Tcl_DStringValue(&utfFilterString);
832                  break;                  break;
833              }              }
834              case FILE_INITDIR: {              case FILE_INITDIR: {
835                  Tcl_DStringFree(&utfDirString);                  Tcl_DStringFree(&utfDirString);
836                  if (Tcl_TranslateFileName(interp, string,                  if (Tcl_TranslateFileName(interp, string,
837                          &utfDirString) == NULL) {                          &utfDirString) == NULL) {
838                      goto end;                      goto end;
839                  }                  }
840                  break;                  break;
841              }              }
842              case FILE_INITFILE: {              case FILE_INITFILE: {
843                  Tcl_DString ds;                  Tcl_DString ds;
844    
845                  if (Tcl_TranslateFileName(interp, string, &ds) == NULL) {                  if (Tcl_TranslateFileName(interp, string, &ds) == NULL) {
846                      goto end;                      goto end;
847                  }                  }
848                  Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds),                  Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds),
849                          Tcl_DStringLength(&ds), 0, NULL, (char *) file,                          Tcl_DStringLength(&ds), 0, NULL, (char *) file,
850                          sizeof(file), NULL, NULL, NULL);                          sizeof(file), NULL, NULL, NULL);
851                  break;                  break;
852              }              }
853              case FILE_PARENT: {              case FILE_PARENT: {
854                  tkwin = Tk_NameToWindow(interp, string, tkwin);                  tkwin = Tk_NameToWindow(interp, string, tkwin);
855                  if (tkwin == NULL) {                  if (tkwin == NULL) {
856                      goto end;                      goto end;
857                  }                  }
858                  break;                  break;
859              }              }
860              case FILE_TITLE: {              case FILE_TITLE: {
861                  title = string;                  title = string;
862                  break;                  break;
863              }              }
864          }          }
865      }      }
866    
867      if (filter == NULL) {      if (filter == NULL) {
868          if (MakeFilter(interp, "", &utfFilterString) != TCL_OK) {          if (MakeFilter(interp, "", &utfFilterString) != TCL_OK) {
869              goto end;              goto end;
870          }          }
871      }      }
872    
873      Tk_MakeWindowExist(tkwin);      Tk_MakeWindowExist(tkwin);
874      hWnd = Tk_GetHWND(Tk_WindowId(tkwin));      hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
875    
876      ofn.lStructSize             = sizeof(ofn);      ofn.lStructSize             = sizeof(ofn);
877      ofn.hwndOwner               = hWnd;      ofn.hwndOwner               = hWnd;
878      ofn.hInstance               = (HINSTANCE) GetWindowLong(ofn.hwndOwner,      ofn.hInstance               = (HINSTANCE) GetWindowLong(ofn.hwndOwner,
879                                          GWL_HINSTANCE);                                          GWL_HINSTANCE);
880      ofn.lpstrFilter             = NULL;      ofn.lpstrFilter             = NULL;
881      ofn.lpstrCustomFilter       = NULL;      ofn.lpstrCustomFilter       = NULL;
882      ofn.nMaxCustFilter          = 0;      ofn.nMaxCustFilter          = 0;
883      ofn.nFilterIndex            = 0;      ofn.nFilterIndex            = 0;
884      ofn.lpstrFile               = (LPTSTR) file;      ofn.lpstrFile               = (LPTSTR) file;
885      ofn.nMaxFile                = MAX_PATH;      ofn.nMaxFile                = MAX_PATH;
886      ofn.lpstrFileTitle          = NULL;      ofn.lpstrFileTitle          = NULL;
887      ofn.nMaxFileTitle           = 0;      ofn.nMaxFileTitle           = 0;
888      ofn.lpstrInitialDir         = NULL;      ofn.lpstrInitialDir         = NULL;
889      ofn.lpstrTitle              = NULL;      ofn.lpstrTitle              = NULL;
890      ofn.Flags                   = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST      ofn.Flags                   = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST
891                                    | OFN_NOCHANGEDIR | OFN_EXPLORER;                                    | OFN_NOCHANGEDIR | OFN_EXPLORER;
892      ofn.nFileOffset             = 0;      ofn.nFileOffset             = 0;
893      ofn.nFileExtension          = 0;      ofn.nFileExtension          = 0;
894      ofn.lpstrDefExt             = NULL;      ofn.lpstrDefExt             = NULL;
895      ofn.lpfnHook                = OFNHookProc;      ofn.lpfnHook                = OFNHookProc;
896      ofn.lCustData               = (LPARAM) interp;      ofn.lCustData               = (LPARAM) interp;
897      ofn.lpTemplateName          = NULL;      ofn.lpTemplateName          = NULL;
898    
899      if (open != 0) {      if (open != 0) {
900          ofn.Flags |= OFN_FILEMUSTEXIST;          ofn.Flags |= OFN_FILEMUSTEXIST;
901      } else {      } else {
902          ofn.Flags |= OFN_OVERWRITEPROMPT;          ofn.Flags |= OFN_OVERWRITEPROMPT;
903      }      }
904    
905      if (tsdPtr->debugFlag != 0) {      if (tsdPtr->debugFlag != 0) {
906          ofn.Flags |= OFN_ENABLEHOOK;          ofn.Flags |= OFN_ENABLEHOOK;
907      }      }
908    
909      if (extension != NULL) {      if (extension != NULL) {
910          Tcl_UtfToExternalDString(NULL, extension, -1, &extString);          Tcl_UtfToExternalDString(NULL, extension, -1, &extString);
911          ofn.lpstrDefExt = (LPTSTR) Tcl_DStringValue(&extString);          ofn.lpstrDefExt = (LPTSTR) Tcl_DStringValue(&extString);
912      }      }
913      Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfFilterString),      Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfFilterString),
914              Tcl_DStringLength(&utfFilterString), &filterString);              Tcl_DStringLength(&utfFilterString), &filterString);
915      ofn.lpstrFilter = (LPTSTR) Tcl_DStringValue(&filterString);      ofn.lpstrFilter = (LPTSTR) Tcl_DStringValue(&filterString);
916    
917      if (Tcl_DStringValue(&utfDirString)[0] != '\0') {      if (Tcl_DStringValue(&utfDirString)[0] != '\0') {
918          Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString),          Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString),
919                  Tcl_DStringLength(&utfDirString), &dirString);                  Tcl_DStringLength(&utfDirString), &dirString);
920          ofn.lpstrInitialDir = (LPTSTR) Tcl_DStringValue(&dirString);          ofn.lpstrInitialDir = (LPTSTR) Tcl_DStringValue(&dirString);
921      }      }
922      if (title != NULL) {      if (title != NULL) {
923          Tcl_UtfToExternalDString(NULL, title, -1, &titleString);          Tcl_UtfToExternalDString(NULL, title, -1, &titleString);
924          ofn.lpstrTitle = (LPTSTR) Tcl_DStringValue(&titleString);          ofn.lpstrTitle = (LPTSTR) Tcl_DStringValue(&titleString);
925      }      }
926    
927      /*      /*
928       * Popup the dialog.         * Popup the dialog.  
929       */       */
930    
931      GetCurrentDirectory(MAX_PATH, savePath);      GetCurrentDirectory(MAX_PATH, savePath);
932      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
933      if (open != 0) {      if (open != 0) {
934          winCode = GetOpenFileName(&ofn);          winCode = GetOpenFileName(&ofn);
935      } else {      } else {
936          winCode = GetSaveFileName(&ofn);          winCode = GetSaveFileName(&ofn);
937      }      }
938      Tcl_SetServiceMode(oldMode);      Tcl_SetServiceMode(oldMode);
939      SetCurrentDirectory(savePath);      SetCurrentDirectory(savePath);
940    
941      /*      /*
942       * Ensure that hWnd is enabled, because it can happen that we       * Ensure that hWnd is enabled, because it can happen that we
943       * have updated the wrapper of the parent, which causes us to       * have updated the wrapper of the parent, which causes us to
944       * leave this child disabled (Windows loses sync).       * leave this child disabled (Windows loses sync).
945       */       */
946      EnableWindow(hWnd, 1);      EnableWindow(hWnd, 1);
947    
948      /*      /*
949       * Clear the interp result since anything may have happened during the       * Clear the interp result since anything may have happened during the
950       * modal loop.       * modal loop.
951       */       */
952    
953      Tcl_ResetResult(interp);      Tcl_ResetResult(interp);
954    
955      /*      /*
956       * Process the results.       * Process the results.
957       */       */
958    
959      if (winCode != 0) {      if (winCode != 0) {
960          char *p;          char *p;
961          Tcl_DString ds;          Tcl_DString ds;
962    
963          Tcl_ExternalToUtfDString(NULL, (char *) ofn.lpstrFile, -1, &ds);          Tcl_ExternalToUtfDString(NULL, (char *) ofn.lpstrFile, -1, &ds);
964          for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) {          for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) {
965              /*              /*
966               * Change the pathname to the Tcl "normalized" pathname, where               * Change the pathname to the Tcl "normalized" pathname, where
967               * back slashes are used instead of forward slashes               * back slashes are used instead of forward slashes
968               */               */
969              if (*p == '\\') {              if (*p == '\\') {
970                  *p = '/';                  *p = '/';
971              }              }
972          }          }
973          Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);          Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);
974          Tcl_DStringFree(&ds);          Tcl_DStringFree(&ds);
975      }      }
976    
977      if (ofn.lpstrTitle != NULL) {      if (ofn.lpstrTitle != NULL) {
978          Tcl_DStringFree(&titleString);          Tcl_DStringFree(&titleString);
979      }      }
980      if (ofn.lpstrInitialDir != NULL) {      if (ofn.lpstrInitialDir != NULL) {
981          Tcl_DStringFree(&dirString);          Tcl_DStringFree(&dirString);
982      }      }
983      Tcl_DStringFree(&filterString);      Tcl_DStringFree(&filterString);
984      if (ofn.lpstrDefExt != NULL) {      if (ofn.lpstrDefExt != NULL) {
985          Tcl_DStringFree(&extString);          Tcl_DStringFree(&extString);
986      }      }
987      result = TCL_OK;      result = TCL_OK;
988    
989      end:      end:
990      Tcl_DStringFree(&utfDirString);      Tcl_DStringFree(&utfDirString);
991      Tcl_DStringFree(&utfFilterString);      Tcl_DStringFree(&utfFilterString);
992    
993      return result;      return result;
994  }  }
995    
996  /*  /*
997   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
998   *   *
999   * OFNHookProc --   * OFNHookProc --
1000   *   *
1001   *      Hook procedure called only if debugging is turned on.  Sets   *      Hook procedure called only if debugging is turned on.  Sets
1002   *      the "tk_dialog" variable when the dialog is ready to receive   *      the "tk_dialog" variable when the dialog is ready to receive
1003   *      messages.   *      messages.
1004   *   *
1005   * Results:   * Results:
1006   *      Returns 0 to allow default processing of messages to occur.   *      Returns 0 to allow default processing of messages to occur.
1007   *   *
1008   * Side effects:   * Side effects:
1009   *      None.   *      None.
1010   *   *
1011   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
1012   */   */
1013    
1014  static UINT APIENTRY  static UINT APIENTRY
1015  OFNHookProc(  OFNHookProc(
1016      HWND hdlg,          // handle to child dialog window      HWND hdlg,          // handle to child dialog window
1017      UINT uMsg,          // message identifier      UINT uMsg,          // message identifier
1018      WPARAM wParam,      // message parameter      WPARAM wParam,      // message parameter
1019      LPARAM lParam)      // message parameter      LPARAM lParam)      // message parameter
1020  {  {
1021      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1022              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1023      OPENFILENAME *ofnPtr;      OPENFILENAME *ofnPtr;
1024    
1025      if (uMsg == WM_INITDIALOG) {      if (uMsg == WM_INITDIALOG) {
1026          SetWindowLong(hdlg, GWL_USERDATA, lParam);          SetWindowLong(hdlg, GWL_USERDATA, lParam);
1027      } else if (uMsg == WM_WINDOWPOSCHANGED) {      } else if (uMsg == WM_WINDOWPOSCHANGED) {
1028          /*          /*
1029           * This message is delivered at the right time to both           * This message is delivered at the right time to both
1030           * old-style and explorer-style hook procs to enable Tk           * old-style and explorer-style hook procs to enable Tk
1031           * to set the debug information.  Unhooks itself so it           * to set the debug information.  Unhooks itself so it
1032           * won't set the debug information every time it gets a           * won't set the debug information every time it gets a
1033           * WM_WINDOWPOSCHANGED message.           * WM_WINDOWPOSCHANGED message.
1034           */           */
1035    
1036          ofnPtr = (OPENFILENAME *) GetWindowLong(hdlg, GWL_USERDATA);          ofnPtr = (OPENFILENAME *) GetWindowLong(hdlg, GWL_USERDATA);
1037          if (ofnPtr != NULL) {          if (ofnPtr != NULL) {
1038              if (ofnPtr->Flags & OFN_EXPLORER) {              if (ofnPtr->Flags & OFN_EXPLORER) {
1039                  hdlg = GetParent(hdlg);                  hdlg = GetParent(hdlg);
1040              }              }
1041              tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData;              tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData;
1042              Tcl_DoWhenIdle(SetTkDialog, (ClientData) hdlg);              Tcl_DoWhenIdle(SetTkDialog, (ClientData) hdlg);
1043              SetWindowLong(hdlg, GWL_USERDATA, (LPARAM) NULL);              SetWindowLong(hdlg, GWL_USERDATA, (LPARAM) NULL);
1044          }          }
1045      }      }
1046      return 0;      return 0;
1047  }  }
1048    
1049  /*  /*
1050   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1051   *   *
1052   * MakeFilter --   * MakeFilter --
1053   *   *
1054   *      Allocate a buffer to store the filters in a format understood by   *      Allocate a buffer to store the filters in a format understood by
1055   *      Windows   *      Windows
1056   *   *
1057   * Results:   * Results:
1058   *      A standard TCL return value.   *      A standard TCL return value.
1059   *   *
1060   * Side effects:   * Side effects:
1061   *      ofnPtr->lpstrFilter is modified.   *      ofnPtr->lpstrFilter is modified.
1062   *   *
1063   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1064   */   */
1065  static int  static int
1066  MakeFilter(interp, string, dsPtr)  MakeFilter(interp, string, dsPtr)
1067      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
1068      char *string;               /* String value of the -filetypes option */      char *string;               /* String value of the -filetypes option */
1069      Tcl_DString *dsPtr;         /* Filled with windows filter string. */      Tcl_DString *dsPtr;         /* Filled with windows filter string. */
1070  {  {
1071      char *filterStr;      char *filterStr;
1072      char *p;      char *p;
1073      int pass;      int pass;
1074      FileFilterList flist;      FileFilterList flist;
1075      FileFilter *filterPtr;      FileFilter *filterPtr;
1076    
1077      TkInitFileFilters(&flist);      TkInitFileFilters(&flist);
1078      if (TkGetFileFilters(interp, &flist, string, 1) != TCL_OK) {      if (TkGetFileFilters(interp, &flist, string, 1) != TCL_OK) {
1079          return TCL_ERROR;          return TCL_ERROR;
1080      }      }
1081    
1082      if (flist.filters == NULL) {      if (flist.filters == NULL) {
1083          /*          /*
1084           * Use "All Files (*.*) as the default filter if none is specified           * Use "All Files (*.*) as the default filter if none is specified
1085           */           */
1086          char *defaultFilter = "All Files (*.*)";          char *defaultFilter = "All Files (*.*)";
1087    
1088          p = filterStr = (char*)ckalloc(30 * sizeof(char));          p = filterStr = (char*)ckalloc(30 * sizeof(char));
1089    
1090          strcpy(p, defaultFilter);          strcpy(p, defaultFilter);
1091          p+= strlen(defaultFilter);          p+= strlen(defaultFilter);
1092    
1093          *p++ = '\0';          *p++ = '\0';
1094          *p++ = '*';          *p++ = '*';
1095          *p++ = '.';          *p++ = '.';
1096          *p++ = '*';          *p++ = '*';
1097          *p++ = '\0';          *p++ = '\0';
1098          *p++ = '\0';          *p++ = '\0';
1099          *p = '\0';          *p = '\0';
1100    
1101      } else {      } else {
1102          /* We format the filetype into a string understood by Windows:          /* We format the filetype into a string understood by Windows:
1103           * {"Text Documents" {.doc .txt} {TEXT}} becomes           * {"Text Documents" {.doc .txt} {TEXT}} becomes
1104           * "Text Documents (*.doc,*.txt)\0*.doc;*.txt\0"           * "Text Documents (*.doc,*.txt)\0*.doc;*.txt\0"
1105           *           *
1106           * See the Windows OPENFILENAME manual page for details on the filter           * See the Windows OPENFILENAME manual page for details on the filter
1107           * string format.           * string format.
1108           */           */
1109    
1110          /*          /*
1111           * Since we may only add asterisks (*) to the filter, we need at most           * Since we may only add asterisks (*) to the filter, we need at most
1112           * twice the size of the string to format the filter           * twice the size of the string to format the filter
1113           */           */
1114          filterStr = ckalloc(strlen(string) * 3);          filterStr = ckalloc(strlen(string) * 3);
1115    
1116          for (filterPtr = flist.filters, p = filterStr; filterPtr;          for (filterPtr = flist.filters, p = filterStr; filterPtr;
1117                  filterPtr = filterPtr->next) {                  filterPtr = filterPtr->next) {
1118              char *sep;              char *sep;
1119              FileFilterClause *clausePtr;              FileFilterClause *clausePtr;
1120    
1121              /*              /*
1122               *  First, put in the name of the file type               *  First, put in the name of the file type
1123               */               */
1124              strcpy(p, filterPtr->name);              strcpy(p, filterPtr->name);
1125              p+= strlen(filterPtr->name);              p+= strlen(filterPtr->name);
1126              *p++ = ' ';              *p++ = ' ';
1127              *p++ = '(';              *p++ = '(';
1128    
1129              for (pass = 1; pass <= 2; pass++) {              for (pass = 1; pass <= 2; pass++) {
1130                  /*                  /*
1131                   * In the first pass, we format the extensions in the                   * In the first pass, we format the extensions in the
1132                   * name field. In the second pass, we format the extensions in                   * name field. In the second pass, we format the extensions in
1133                   * the filter pattern field                   * the filter pattern field
1134                   */                   */
1135                  sep = "";                  sep = "";
1136                  for (clausePtr=filterPtr->clauses;clausePtr;                  for (clausePtr=filterPtr->clauses;clausePtr;
1137                           clausePtr=clausePtr->next) {                           clausePtr=clausePtr->next) {
1138                      GlobPattern *globPtr;                      GlobPattern *globPtr;
1139                                    
1140    
1141                      for (globPtr=clausePtr->patterns; globPtr;                      for (globPtr=clausePtr->patterns; globPtr;
1142                              globPtr=globPtr->next) {                              globPtr=globPtr->next) {
1143                          strcpy(p, sep);                          strcpy(p, sep);
1144                          p+= strlen(sep);                          p+= strlen(sep);
1145                          strcpy(p, globPtr->pattern);                          strcpy(p, globPtr->pattern);
1146                          p+= strlen(globPtr->pattern);                          p+= strlen(globPtr->pattern);
1147    
1148                          if (pass==1) {                          if (pass==1) {
1149                              sep = ",";                              sep = ",";
1150                          } else {                          } else {
1151                              sep = ";";                              sep = ";";
1152                          }                          }
1153                      }                      }
1154                  }                  }
1155                  if (pass == 1) {                  if (pass == 1) {
1156                      if (pass == 1) {                      if (pass == 1) {
1157                          *p ++ = ')';                          *p ++ = ')';
1158                      }                      }
1159                  }                  }
1160                  *p ++ = '\0';                  *p ++ = '\0';
1161              }              }
1162          }          }
1163    
1164          /*          /*
1165           * Windows requires the filter string to be ended by two NULL           * Windows requires the filter string to be ended by two NULL
1166           * characters.           * characters.
1167           */           */
1168          *p++ = '\0';          *p++ = '\0';
1169          *p = '\0';          *p = '\0';
1170      }      }
1171    
1172      Tcl_DStringAppend(dsPtr, filterStr, p - filterStr);      Tcl_DStringAppend(dsPtr, filterStr, p - filterStr);
1173      ckfree((char *) filterStr);      ckfree((char *) filterStr);
1174    
1175      TkFreeFileFilters(&flist);      TkFreeFileFilters(&flist);
1176      return TCL_OK;      return TCL_OK;
1177  }  }
1178    
1179  /*  /*
1180   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1181   *   *
1182   * Tk_ChooseDirectoryObjCmd --   * Tk_ChooseDirectoryObjCmd --
1183   *   *
1184   *      This procedure implements the "tk_chooseDirectory" dialog box   *      This procedure implements the "tk_chooseDirectory" dialog box
1185   *      for the Windows platform. See the user documentation for details   *      for the Windows platform. See the user documentation for details
1186   *      on what it does.   *      on what it does.
1187   *   *
1188   * Results:   * Results:
1189   *      See user documentation.   *      See user documentation.
1190   *   *
1191   * Side effects:   * Side effects:
1192   *      A modal dialog window is created.  Tcl_SetServiceMode() is   *      A modal dialog window is created.  Tcl_SetServiceMode() is
1193   *      called to allow background events to be processed   *      called to allow background events to be processed
1194   *   *
1195   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1196   */   */
1197    
1198  int  int
1199  Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv)  Tk_ChooseDirectoryObjCmd(clientData, interp, objc, objv)
1200      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
1201      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
1202      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
1203      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
1204  {  {
1205      OPENFILENAME ofn;      OPENFILENAME ofn;
1206      TCHAR path[MAX_PATH], savePath[MAX_PATH];      TCHAR path[MAX_PATH], savePath[MAX_PATH];
1207      ChooseDir cd;      ChooseDir cd;
1208      int result, mustExist, code, mode, i;      int result, mustExist, code, mode, i;
1209      Tk_Window tkwin;      Tk_Window tkwin;
1210      HWND hWnd;      HWND hWnd;
1211      char *utfTitle;      char *utfTitle;
1212      Tcl_DString utfDirString;      Tcl_DString utfDirString;
1213      Tcl_DString titleString, dirString;      Tcl_DString titleString, dirString;
1214      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1215              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1216      static char *optionStrings[] = {      static char *optionStrings[] = {
1217          "-initialdir",  "-mustexist",   "-parent",      "-title",          "-initialdir",  "-mustexist",   "-parent",      "-title",
1218          NULL          NULL
1219      };      };
1220      enum options {      enum options {
1221          DIR_INITIAL,    DIR_EXIST,      DIR_PARENT,     FILE_TITLE          DIR_INITIAL,    DIR_EXIST,      DIR_PARENT,     FILE_TITLE
1222      };      };
1223    
1224      if (tsdPtr->WM_LBSELCHANGED == 0) {      if (tsdPtr->WM_LBSELCHANGED == 0) {
1225          tsdPtr->WM_LBSELCHANGED = RegisterWindowMessage(LBSELCHSTRING);          tsdPtr->WM_LBSELCHANGED = RegisterWindowMessage(LBSELCHSTRING);
1226      }      }
1227        
1228      result = TCL_ERROR;      result = TCL_ERROR;
1229      path[0] = '\0';      path[0] = '\0';
1230    
1231      Tcl_DStringInit(&utfDirString);      Tcl_DStringInit(&utfDirString);
1232      mustExist = 0;      mustExist = 0;
1233      tkwin = (Tk_Window) clientData;      tkwin = (Tk_Window) clientData;
1234      utfTitle = NULL;      utfTitle = NULL;
1235    
1236      for (i = 1; i < objc; i += 2) {      for (i = 1; i < objc; i += 2) {
1237          int index;          int index;
1238          char *string;          char *string;
1239          Tcl_Obj *optionPtr, *valuePtr;          Tcl_Obj *optionPtr, *valuePtr;
1240    
1241          optionPtr = objv[i];          optionPtr = objv[i];
1242          valuePtr = objv[i + 1];          valuePtr = objv[i + 1];
1243    
1244          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",
1245                  0, &index) != TCL_OK) {                  0, &index) != TCL_OK) {
1246              goto cleanup;              goto cleanup;
1247          }          }
1248          if (i + 1 == objc) {          if (i + 1 == objc) {
1249              string = Tcl_GetStringFromObj(optionPtr, NULL);              string = Tcl_GetStringFromObj(optionPtr, NULL);
1250              Tcl_AppendResult(interp, "value for \"", string, "\" missing",              Tcl_AppendResult(interp, "value for \"", string, "\" missing",
1251                      (char *) NULL);                      (char *) NULL);
1252              goto cleanup;              goto cleanup;
1253          }          }
1254    
1255          string = Tcl_GetStringFromObj(valuePtr, NULL);          string = Tcl_GetStringFromObj(valuePtr, NULL);
1256          switch ((enum options) index) {          switch ((enum options) index) {
1257              case DIR_INITIAL: {              case DIR_INITIAL: {
1258                  Tcl_DStringFree(&utfDirString);                  Tcl_DStringFree(&utfDirString);
1259                  if (Tcl_TranslateFileName(interp, string,                  if (Tcl_TranslateFileName(interp, string,
1260                          &utfDirString) == NULL) {                          &utfDirString) == NULL) {
1261                      goto cleanup;                      goto cleanup;
1262                  }                  }
1263                  break;                  break;
1264              }              }
1265              case DIR_EXIST: {              case DIR_EXIST: {
1266                  if (Tcl_GetBooleanFromObj(interp, valuePtr, &mustExist) != TCL_OK) {                  if (Tcl_GetBooleanFromObj(interp, valuePtr, &mustExist) != TCL_OK) {
1267                      goto cleanup;                      goto cleanup;
1268                  }                  }
1269                  break;                  break;
1270              }              }
1271              case DIR_PARENT: {              case DIR_PARENT: {
1272                  tkwin = Tk_NameToWindow(interp, string, tkwin);                  tkwin = Tk_NameToWindow(interp, string, tkwin);
1273                  if (tkwin == NULL) {                  if (tkwin == NULL) {
1274                      goto cleanup;                      goto cleanup;
1275                  }                  }
1276                  break;                  break;
1277              }              }
1278              case FILE_TITLE: {              case FILE_TITLE: {
1279                  utfTitle = string;                  utfTitle = string;
1280                  break;                  break;
1281              }              }
1282          }          }
1283      }      }
1284    
1285      Tk_MakeWindowExist(tkwin);      Tk_MakeWindowExist(tkwin);
1286      hWnd = Tk_GetHWND(Tk_WindowId(tkwin));      hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
1287    
1288      cd.interp = interp;      cd.interp = interp;
1289    
1290      ofn.lStructSize             = sizeof(ofn);      ofn.lStructSize             = sizeof(ofn);
1291      ofn.hwndOwner               = hWnd;      ofn.hwndOwner               = hWnd;
1292      ofn.hInstance               = (HINSTANCE) GetWindowLong(ofn.hwndOwner,      ofn.hInstance               = (HINSTANCE) GetWindowLong(ofn.hwndOwner,
1293                                          GWL_HINSTANCE);                                          GWL_HINSTANCE);
1294      ofn.lpstrFilter             = NULL;      ofn.lpstrFilter             = NULL;
1295      ofn.lpstrCustomFilter       = NULL;      ofn.lpstrCustomFilter       = NULL;
1296      ofn.nMaxCustFilter          = 0;      ofn.nMaxCustFilter          = 0;
1297      ofn.nFilterIndex            = 0;      ofn.nFilterIndex            = 0;
1298      ofn.lpstrFile               = NULL; //(TCHAR *) path;      ofn.lpstrFile               = NULL; //(TCHAR *) path;
1299      ofn.nMaxFile                = MAX_PATH;      ofn.nMaxFile                = MAX_PATH;
1300      ofn.lpstrFileTitle          = NULL;      ofn.lpstrFileTitle          = NULL;
1301      ofn.nMaxFileTitle           = 0;      ofn.nMaxFileTitle           = 0;
1302      ofn.lpstrInitialDir         = NULL;      ofn.lpstrInitialDir         = NULL;
1303      ofn.lpstrTitle              = NULL;      ofn.lpstrTitle              = NULL;
1304      ofn.Flags                   = OFN_HIDEREADONLY      ofn.Flags                   = OFN_HIDEREADONLY
1305                                    | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE;                                    | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE;
1306      ofn.nFileOffset             = 0;      ofn.nFileOffset             = 0;
1307      ofn.nFileExtension          = 0;      ofn.nFileExtension          = 0;
1308      ofn.lpstrDefExt             = NULL;      ofn.lpstrDefExt             = NULL;
1309      ofn.lCustData               = (LPARAM) &cd;      ofn.lCustData               = (LPARAM) &cd;
1310      ofn.lpfnHook                = ChooseDirectoryHookProc;      ofn.lpfnHook                = ChooseDirectoryHookProc;
1311      ofn.lpTemplateName          = MAKEINTRESOURCE(FILEOPENORD);      ofn.lpTemplateName          = MAKEINTRESOURCE(FILEOPENORD);
1312    
1313      if (Tcl_DStringValue(&utfDirString)[0] != '\0') {      if (Tcl_DStringValue(&utfDirString)[0] != '\0') {
1314          Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString),          Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString),
1315                  Tcl_DStringLength(&utfDirString), &dirString);                  Tcl_DStringLength(&utfDirString), &dirString);
1316          ofn.lpstrInitialDir = (LPTSTR) Tcl_DStringValue(&dirString);          ofn.lpstrInitialDir = (LPTSTR) Tcl_DStringValue(&dirString);
1317      }      }
1318      if (mustExist) {      if (mustExist) {
1319          ofn.Flags |= OFN_PATHMUSTEXIST;          ofn.Flags |= OFN_PATHMUSTEXIST;
1320      }      }
1321      if (utfTitle != NULL) {      if (utfTitle != NULL) {
1322          Tcl_UtfToExternalDString(NULL, utfTitle, -1, &titleString);          Tcl_UtfToExternalDString(NULL, utfTitle, -1, &titleString);
1323          ofn.lpstrTitle = (LPTSTR) Tcl_DStringValue(&titleString);          ofn.lpstrTitle = (LPTSTR) Tcl_DStringValue(&titleString);
1324      }      }
1325    
1326      /*      /*
1327       * Display dialog.  The choose directory dialog doesn't preserve the       * Display dialog.  The choose directory dialog doesn't preserve the
1328       * current directory, so it must be saved and restored here.       * current directory, so it must be saved and restored here.
1329       */       */
1330            
1331      GetCurrentDirectory(MAX_PATH, savePath);      GetCurrentDirectory(MAX_PATH, savePath);
1332      mode = Tcl_SetServiceMode(TCL_SERVICE_ALL);      mode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
1333      code = GetOpenFileName(&ofn);      code = GetOpenFileName(&ofn);
1334      Tcl_SetServiceMode(mode);      Tcl_SetServiceMode(mode);
1335      SetCurrentDirectory(savePath);      SetCurrentDirectory(savePath);
1336    
1337      /*      /*
1338       * Ensure that hWnd is enabled, because it can happen that we       * Ensure that hWnd is enabled, because it can happen that we
1339       * have updated the wrapper of the parent, which causes us to       * have updated the wrapper of the parent, which causes us to
1340       * leave this child disabled (Windows loses sync).       * leave this child disabled (Windows loses sync).
1341       */       */
1342      EnableWindow(hWnd, 1);      EnableWindow(hWnd, 1);
1343    
1344      Tcl_ResetResult(interp);      Tcl_ResetResult(interp);
1345      if (code != 0) {      if (code != 0) {
1346          /*          /*
1347           * Change the pathname to the Tcl "normalized" pathname, where           * Change the pathname to the Tcl "normalized" pathname, where
1348           * back slashes are used instead of forward slashes           * back slashes are used instead of forward slashes
1349           */           */
1350    
1351          char *p;          char *p;
1352          Tcl_DString ds;          Tcl_DString ds;
1353    
1354          Tcl_ExternalToUtfDString(NULL, (char *) cd.path, -1, &ds);          Tcl_ExternalToUtfDString(NULL, (char *) cd.path, -1, &ds);
1355          for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) {          for (p = Tcl_DStringValue(&ds); *p != '\0'; p++) {
1356              if (*p == '\\') {              if (*p == '\\') {
1357                  *p = '/';                  *p = '/';
1358              }              }
1359          }          }
1360          Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);          Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL);
1361          Tcl_DStringFree(&ds);          Tcl_DStringFree(&ds);
1362      }      }
1363    
1364      if (ofn.lpstrTitle != NULL) {      if (ofn.lpstrTitle != NULL) {
1365          Tcl_DStringFree(&titleString);          Tcl_DStringFree(&titleString);
1366      }      }
1367      if (ofn.lpstrInitialDir != NULL) {      if (ofn.lpstrInitialDir != NULL) {
1368          Tcl_DStringFree(&dirString);          Tcl_DStringFree(&dirString);
1369      }      }
1370      result = TCL_OK;      result = TCL_OK;
1371    
1372      cleanup:      cleanup:
1373      Tcl_DStringFree(&utfDirString);      Tcl_DStringFree(&utfDirString);
1374    
1375      return result;      return result;
1376  }  }
1377    
1378  /*  /*
1379   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1380   *   *
1381   * ChooseDirectoryHookProc --   * ChooseDirectoryHookProc --
1382   *   *
1383   *      Hook procedure called by the ChooseDirectory dialog to modify   *      Hook procedure called by the ChooseDirectory dialog to modify
1384   *      its default behavior.  The ChooseDirectory dialog is really an   *      its default behavior.  The ChooseDirectory dialog is really an
1385   *      OpenFile dialog with certain controls rearranged and certain   *      OpenFile dialog with certain controls rearranged and certain
1386   *      behaviors changed.  For instance, typing a name in the   *      behaviors changed.  For instance, typing a name in the
1387   *      ChooseDirectory dialog selects a directory, rather than   *      ChooseDirectory dialog selects a directory, rather than
1388   *      selecting a file.   *      selecting a file.
1389   *   *
1390   * Results:   * Results:
1391   *      Returns 0 to allow default processing of message, or 1 to   *      Returns 0 to allow default processing of message, or 1 to
1392   *      tell default dialog procedure not to process the message.   *      tell default dialog procedure not to process the message.
1393   *   *
1394   * Side effects:   * Side effects:
1395   *      A dialog window is created the first this procedure is called.   *      A dialog window is created the first this procedure is called.
1396   *      This window is not destroyed and will be reused the next time   *      This window is not destroyed and will be reused the next time
1397   *      the application invokes the "tk_getOpenFile" or   *      the application invokes the "tk_getOpenFile" or
1398   *      "tk_getSaveFile" command.   *      "tk_getSaveFile" command.
1399   *   *
1400   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1401   */   */
1402    
1403  static UINT APIENTRY  static UINT APIENTRY
1404  ChooseDirectoryHookProc(  ChooseDirectoryHookProc(
1405      HWND hwnd,      HWND hwnd,
1406      UINT message,      UINT message,
1407      WPARAM wParam,      WPARAM wParam,
1408      LPARAM lParam)      LPARAM lParam)
1409  {  {
1410      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1411              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1412      OPENFILENAME *ofnPtr;      OPENFILENAME *ofnPtr;
1413    
1414      /*      /*
1415       * GWL_USERDATA keeps track of ofnPtr.       * GWL_USERDATA keeps track of ofnPtr.
1416       */       */
1417            
1418      ofnPtr = (OPENFILENAME *) GetWindowLong(hwnd, GWL_USERDATA);      ofnPtr = (OPENFILENAME *) GetWindowLong(hwnd, GWL_USERDATA);
1419    
1420      if (message == WM_INITDIALOG) {      if (message == WM_INITDIALOG) {
1421          ChooseDir *cdPtr;          ChooseDir *cdPtr;
1422    
1423          SetWindowLong(hwnd, GWL_USERDATA, lParam);          SetWindowLong(hwnd, GWL_USERDATA, lParam);
1424          ofnPtr = (OPENFILENAME *) lParam;          ofnPtr = (OPENFILENAME *) lParam;
1425          cdPtr = (ChooseDir *) ofnPtr->lCustData;          cdPtr = (ChooseDir *) ofnPtr->lCustData;
1426          cdPtr->lastCtrl = 0;          cdPtr->lastCtrl = 0;
1427          cdPtr->lastIdx = 1000;          cdPtr->lastIdx = 1000;
1428          cdPtr->path[0] = '\0';          cdPtr->path[0] = '\0';
1429    
1430          if (ofnPtr->lpstrInitialDir == NULL) {          if (ofnPtr->lpstrInitialDir == NULL) {
1431              GetCurrentDirectory(MAX_PATH, cdPtr->path);              GetCurrentDirectory(MAX_PATH, cdPtr->path);
1432          } else {          } else {
1433              lstrcpy(cdPtr->path, ofnPtr->lpstrInitialDir);              lstrcpy(cdPtr->path, ofnPtr->lpstrInitialDir);
1434          }          }
1435          SetDlgItemText(hwnd, edt10, cdPtr->path);          SetDlgItemText(hwnd, edt10, cdPtr->path);
1436          SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);          SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);
1437          if (tsdPtr->debugFlag) {          if (tsdPtr->debugFlag) {
1438              tsdPtr->debugInterp = cdPtr->interp;              tsdPtr->debugInterp = cdPtr->interp;
1439              Tcl_DoWhenIdle(SetTkDialog, (ClientData) hwnd);              Tcl_DoWhenIdle(SetTkDialog, (ClientData) hwnd);
1440          }          }
1441          return 0;          return 0;
1442      }      }
1443      if (ofnPtr == NULL) {      if (ofnPtr == NULL) {
1444          return 0;          return 0;
1445      }      }
1446    
1447      if (message == tsdPtr->WM_LBSELCHANGED) {      if (message == tsdPtr->WM_LBSELCHANGED) {
1448          /*          /*
1449           * Called when double-clicking on directory.           * Called when double-clicking on directory.
1450           * If directory wasn't already open, browse that directory.           * If directory wasn't already open, browse that directory.
1451           * If directory was already open, return selected directory.           * If directory was already open, return selected directory.
1452           */           */
1453    
1454          ChooseDir *cdPtr;          ChooseDir *cdPtr;
1455          int idCtrl, thisItem;          int idCtrl, thisItem;
1456    
1457          idCtrl = (int) wParam;          idCtrl = (int) wParam;
1458          thisItem = LOWORD(lParam);          thisItem = LOWORD(lParam);
1459          cdPtr = (ChooseDir *) ofnPtr->lCustData;          cdPtr = (ChooseDir *) ofnPtr->lCustData;
1460    
1461          GetCurrentDirectory(MAX_PATH, cdPtr->path);          GetCurrentDirectory(MAX_PATH, cdPtr->path);
1462          if (idCtrl == lst2) {          if (idCtrl == lst2) {
1463              if (cdPtr->lastIdx == thisItem) {              if (cdPtr->lastIdx == thisItem) {
1464                  EndDialog(hwnd, IDOK);                  EndDialog(hwnd, IDOK);
1465                  return 1;                  return 1;
1466              }              }
1467              cdPtr->lastIdx = thisItem;              cdPtr->lastIdx = thisItem;
1468          }          }
1469          SetDlgItemText(hwnd, edt10, cdPtr->path);          SetDlgItemText(hwnd, edt10, cdPtr->path);
1470          SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);          SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);
1471      } else if (message == WM_COMMAND) {      } else if (message == WM_COMMAND) {
1472          ChooseDir *cdPtr;          ChooseDir *cdPtr;
1473          int idCtrl, notifyCode;          int idCtrl, notifyCode;
1474    
1475          idCtrl = LOWORD(wParam);          idCtrl = LOWORD(wParam);
1476          notifyCode = HIWORD(wParam);          notifyCode = HIWORD(wParam);
1477          cdPtr = (ChooseDir *) ofnPtr->lCustData;          cdPtr = (ChooseDir *) ofnPtr->lCustData;
1478    
1479          if ((idCtrl != IDOK) || (notifyCode != BN_CLICKED)) {          if ((idCtrl != IDOK) || (notifyCode != BN_CLICKED)) {
1480              /*              /*
1481               * OK Button wasn't clicked.  Do the default.               * OK Button wasn't clicked.  Do the default.
1482               */               */
1483    
1484              if ((idCtrl == lst2) || (idCtrl == edt10)) {              if ((idCtrl == lst2) || (idCtrl == edt10)) {
1485                  cdPtr->lastCtrl = idCtrl;                  cdPtr->lastCtrl = idCtrl;
1486              }              }
1487              return 0;              return 0;
1488          }          }
1489    
1490          /*          /*
1491           * Dialogs also get the message that OK was clicked when Enter           * Dialogs also get the message that OK was clicked when Enter
1492           * is pressed in some other control.  Find out what window           * is pressed in some other control.  Find out what window
1493           * we were really in when we got the supposed "OK", because the           * we were really in when we got the supposed "OK", because the
1494           * behavior is different.           * behavior is different.
1495           */           */
1496    
1497          if (cdPtr->lastCtrl == edt10) {          if (cdPtr->lastCtrl == edt10) {
1498              /*              /*
1499               * Hit Enter or clicked OK while typing a directory name in the               * Hit Enter or clicked OK while typing a directory name in the
1500               * edit control.               * edit control.
1501               * If it's a new name, try to go to that directory.               * If it's a new name, try to go to that directory.
1502               * If the name hasn't changed since last time, return selected               * If the name hasn't changed since last time, return selected
1503               * directory.               * directory.
1504               */               */
1505    
1506              int changed;              int changed;
1507              TCHAR tmp[MAX_PATH];              TCHAR tmp[MAX_PATH];
1508    
1509              if (GetDlgItemText(hwnd, edt10, tmp, MAX_PATH) == 0) {              if (GetDlgItemText(hwnd, edt10, tmp, MAX_PATH) == 0) {
1510                  return 0;                  return 0;
1511              }              }
1512    
1513              changed = lstrcmp(cdPtr->path, tmp);              changed = lstrcmp(cdPtr->path, tmp);
1514              lstrcpy(cdPtr->path, tmp);              lstrcpy(cdPtr->path, tmp);
1515    
1516              if (SetCurrentDirectory(cdPtr->path) == 0) {              if (SetCurrentDirectory(cdPtr->path) == 0) {
1517                  /*                  /*
1518                   * Non-existent directory.                   * Non-existent directory.
1519                   */                   */
1520    
1521                  if (ofnPtr->Flags & OFN_PATHMUSTEXIST) {                  if (ofnPtr->Flags & OFN_PATHMUSTEXIST) {
1522                      /*                      /*
1523                       * Directory must exist.  Complain, then rehighlight text.                       * Directory must exist.  Complain, then rehighlight text.
1524                       */                       */
1525    
1526                      wsprintf(tmp, _T("Cannot change directory to \"%.200s\"."),                      wsprintf(tmp, _T("Cannot change directory to \"%.200s\"."),
1527                              cdPtr->path);                              cdPtr->path);
1528                      MessageBox(hwnd, tmp, NULL, MB_OK);                      MessageBox(hwnd, tmp, NULL, MB_OK);
1529                      SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);                      SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);
1530                      return 0;                      return 0;
1531                  }                  }
1532                  if (changed) {                  if (changed) {
1533                      /*                      /*
1534                       * Directory was invalid, but we want to keep displaying                       * Directory was invalid, but we want to keep displaying
1535                       * this name.  Don't update the listbox that displays the                       * this name.  Don't update the listbox that displays the
1536                       * current directory heirarchy, or it'll erase the name.                       * current directory heirarchy, or it'll erase the name.
1537                       */                       */
1538                                            
1539                      SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);                      SendDlgItemMessage(hwnd, edt10, EM_SETSEL, 0, -1);
1540                      return 0;                      return 0;
1541                  }                  }
1542              }              }
1543              if (changed == 0) {              if (changed == 0) {
1544                  /*                  /*
1545                   * Name hasn't changed since the last time we hit return                   * Name hasn't changed since the last time we hit return
1546                   * or double-clicked on a directory, so return this.                   * or double-clicked on a directory, so return this.
1547                   */                   */
1548    
1549                  EndDialog(hwnd, IDOK);                  EndDialog(hwnd, IDOK);
1550                  return 1;                  return 1;
1551              }              }
1552                            
1553              cdPtr->lastCtrl = IDOK;              cdPtr->lastCtrl = IDOK;
1554    
1555              /*              /*
1556               * The following is the magic code, determined by running               * The following is the magic code, determined by running
1557               * Spy++ on some other directory chooser, that it takes to               * Spy++ on some other directory chooser, that it takes to
1558               * get this dialog to update the listbox to display the               * get this dialog to update the listbox to display the
1559               * current directory.               * current directory.
1560               */               */
1561    
1562              SetDlgItemText(hwnd, edt1, cdPtr->path);              SetDlgItemText(hwnd, edt1, cdPtr->path);
1563              SendMessage(hwnd, WM_COMMAND, (WPARAM) MAKELONG(cmb2, 0x8003),              SendMessage(hwnd, WM_COMMAND, (WPARAM) MAKELONG(cmb2, 0x8003),
1564                      (LPARAM) GetDlgItem(hwnd, cmb2));                      (LPARAM) GetDlgItem(hwnd, cmb2));
1565              return 0;              return 0;
1566          } else if (idCtrl == lst2) {          } else if (idCtrl == lst2) {
1567              /*              /*
1568               * Enter key was pressed while in listbox.                 * Enter key was pressed while in listbox.  
1569               * If it's a new directory, allow default behavior to open dir.               * If it's a new directory, allow default behavior to open dir.
1570               * If the directory hasn't changed, return selected directory.               * If the directory hasn't changed, return selected directory.
1571               */               */
1572    
1573              int thisItem;              int thisItem;
1574    
1575              thisItem = (int) SendDlgItemMessage(hwnd, lst2, LB_GETCURSEL, 0, 0);              thisItem = (int) SendDlgItemMessage(hwnd, lst2, LB_GETCURSEL, 0, 0);
1576              if (cdPtr->lastIdx == thisItem) {              if (cdPtr->lastIdx == thisItem) {
1577                  GetCurrentDirectory(MAX_PATH, cdPtr->path);                  GetCurrentDirectory(MAX_PATH, cdPtr->path);
1578                  EndDialog(hwnd, IDOK);                  EndDialog(hwnd, IDOK);
1579                  return 1;                  return 1;
1580              }              }
1581          } else if (idCtrl == IDOK) {          } else if (idCtrl == IDOK) {
1582              /*              /*
1583               * The OK button was clicked. Return the value currently selected               * The OK button was clicked. Return the value currently selected
1584               * in the entry.               * in the entry.
1585               */               */
1586    
1587              GetCurrentDirectory(MAX_PATH, cdPtr->path);              GetCurrentDirectory(MAX_PATH, cdPtr->path);
1588              EndDialog(hwnd, IDOK);              EndDialog(hwnd, IDOK);
1589              return 1;              return 1;
1590          }          }
1591      }      }
1592      return 0;      return 0;
1593  }  }
1594    
1595  /*  /*
1596   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1597   *   *
1598   * Tk_MessageBoxObjCmd --   * Tk_MessageBoxObjCmd --
1599   *   *
1600   *      This procedure implements the MessageBox window for the   *      This procedure implements the MessageBox window for the
1601   *      Windows platform. See the user documentation for details on what   *      Windows platform. See the user documentation for details on what
1602   *      it does.   *      it does.
1603   *   *
1604   * Results:   * Results:
1605   *      See user documentation.   *      See user documentation.
1606   *   *
1607   * Side effects:   * Side effects:
1608   *      None. The MessageBox window will be destroy before this procedure   *      None. The MessageBox window will be destroy before this procedure
1609   *      returns.   *      returns.
1610   *   *
1611   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1612   */   */
1613    
1614  int  int
1615  Tk_MessageBoxObjCmd(clientData, interp, objc, objv)  Tk_MessageBoxObjCmd(clientData, interp, objc, objv)
1616      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
1617      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
1618      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
1619      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
1620  {  {
1621      Tk_Window tkwin, parent;      Tk_Window tkwin, parent;
1622      HWND hWnd;      HWND hWnd;
1623      char *message, *title;      char *message, *title;
1624      int defaultBtn, icon, type;      int defaultBtn, icon, type;
1625      int i, oldMode, flags, winCode;      int i, oldMode, flags, winCode;
1626      Tcl_DString messageString, titleString;      Tcl_DString messageString, titleString;
1627      static char *optionStrings[] = {      static char *optionStrings[] = {
1628          "-default",     "-icon",        "-message",     "-parent",          "-default",     "-icon",        "-message",     "-parent",
1629          "-title",       "-type",        NULL          "-title",       "-type",        NULL
1630      };      };
1631      enum options {      enum options {
1632          MSG_DEFAULT,    MSG_ICON,       MSG_MESSAGE,    MSG_PARENT,          MSG_DEFAULT,    MSG_ICON,       MSG_MESSAGE,    MSG_PARENT,
1633          MSG_TITLE,      MSG_TYPE          MSG_TITLE,      MSG_TYPE
1634      };      };
1635    
1636      tkwin = (Tk_Window) clientData;      tkwin = (Tk_Window) clientData;
1637    
1638      defaultBtn  = -1;      defaultBtn  = -1;
1639      icon        = MB_ICONINFORMATION;      icon        = MB_ICONINFORMATION;
1640      message     = NULL;      message     = NULL;
1641      parent      = tkwin;      parent      = tkwin;
1642      title       = NULL;      title       = NULL;
1643      type        = MB_OK;      type        = MB_OK;
1644    
1645      for (i = 1; i < objc; i += 2) {      for (i = 1; i < objc; i += 2) {
1646          int index;          int index;
1647          char *string;          char *string;
1648          Tcl_Obj *optionPtr, *valuePtr;          Tcl_Obj *optionPtr, *valuePtr;
1649    
1650          optionPtr = objv[i];          optionPtr = objv[i];
1651          valuePtr = objv[i + 1];          valuePtr = objv[i + 1];
1652    
1653          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",          if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option",
1654                  TCL_EXACT, &index) != TCL_OK) {                  TCL_EXACT, &index) != TCL_OK) {
1655              return TCL_ERROR;              return TCL_ERROR;
1656          }          }
1657          if (i + 1 == objc) {          if (i + 1 == objc) {
1658              string = Tcl_GetStringFromObj(optionPtr, NULL);              string = Tcl_GetStringFromObj(optionPtr, NULL);
1659              Tcl_AppendResult(interp, "value for \"", string, "\" missing",              Tcl_AppendResult(interp, "value for \"", string, "\" missing",
1660                      (char *) NULL);                      (char *) NULL);
1661              return TCL_ERROR;              return TCL_ERROR;
1662          }          }
1663    
1664          string = Tcl_GetStringFromObj(valuePtr, NULL);          string = Tcl_GetStringFromObj(valuePtr, NULL);
1665          switch ((enum options) index) {          switch ((enum options) index) {
1666          case MSG_DEFAULT:          case MSG_DEFAULT:
1667              defaultBtn = TkFindStateNumObj(interp, optionPtr, buttonMap,              defaultBtn = TkFindStateNumObj(interp, optionPtr, buttonMap,
1668                      valuePtr);                      valuePtr);
1669              if (defaultBtn < 0) {              if (defaultBtn < 0) {
1670                  return TCL_ERROR;                  return TCL_ERROR;
1671              }              }
1672              break;              break;
1673    
1674          case MSG_ICON:          case MSG_ICON:
1675              icon = TkFindStateNumObj(interp, optionPtr, iconMap, valuePtr);              icon = TkFindStateNumObj(interp, optionPtr, iconMap, valuePtr);
1676              if (icon < 0) {              if (icon < 0) {
1677                  return TCL_ERROR;                  return TCL_ERROR;
1678              }              }
1679              break;              break;
1680    
1681          case MSG_MESSAGE:          case MSG_MESSAGE:
1682              message = string;              message = string;
1683              break;              break;
1684    
1685          case MSG_PARENT:          case MSG_PARENT:
1686              parent = Tk_NameToWindow(interp, string, tkwin);              parent = Tk_NameToWindow(interp, string, tkwin);
1687              if (parent == NULL) {              if (parent == NULL) {
1688                  return TCL_ERROR;                  return TCL_ERROR;
1689              }              }
1690              break;              break;
1691    
1692          case MSG_TITLE:          case MSG_TITLE:
1693              title = string;              title = string;
1694              break;              break;
1695    
1696          case MSG_TYPE:          case MSG_TYPE:
1697              type = TkFindStateNumObj(interp, optionPtr, typeMap, valuePtr);              type = TkFindStateNumObj(interp, optionPtr, typeMap, valuePtr);
1698              if (type < 0) {              if (type < 0) {
1699                  return TCL_ERROR;                  return TCL_ERROR;
1700              }              }
1701              break;              break;
1702    
1703          }          }
1704      }      }
1705    
1706      Tk_MakeWindowExist(parent);      Tk_MakeWindowExist(parent);
1707      hWnd = Tk_GetHWND(Tk_WindowId(parent));      hWnd = Tk_GetHWND(Tk_WindowId(parent));
1708            
1709      flags = 0;      flags = 0;
1710      if (defaultBtn >= 0) {      if (defaultBtn >= 0) {
1711          int defaultBtnIdx;          int defaultBtnIdx;
1712    
1713          defaultBtnIdx = -1;          defaultBtnIdx = -1;
1714          for (i = 0; i < NUM_TYPES; i++) {          for (i = 0; i < NUM_TYPES; i++) {
1715              if (type == allowedTypes[i].type) {              if (type == allowedTypes[i].type) {
1716                  int j;                  int j;
1717    
1718                  for (j = 0; j < 3; j++) {                  for (j = 0; j < 3; j++) {
1719                      if (allowedTypes[i].btnIds[j] == defaultBtn) {                      if (allowedTypes[i].btnIds[j] == defaultBtn) {
1720                          defaultBtnIdx = j;                          defaultBtnIdx = j;
1721                          break;                          break;
1722                      }                      }
1723                  }                  }
1724                  if (defaultBtnIdx < 0) {                  if (defaultBtnIdx < 0) {
1725                      Tcl_AppendResult(interp, "invalid default button \"",                      Tcl_AppendResult(interp, "invalid default button \"",
1726                              TkFindStateString(buttonMap, defaultBtn),                              TkFindStateString(buttonMap, defaultBtn),
1727                              "\"", NULL);                              "\"", NULL);
1728                      return TCL_ERROR;                      return TCL_ERROR;
1729                  }                  }
1730                  break;                  break;
1731              }              }
1732          }          }
1733          flags = buttonFlagMap[defaultBtnIdx];          flags = buttonFlagMap[defaultBtnIdx];
1734      }      }
1735    
1736      flags |= icon | type | MB_SYSTEMMODAL;      flags |= icon | type | MB_SYSTEMMODAL;
1737    
1738      Tcl_UtfToExternalDString(NULL, message, -1, &messageString);      Tcl_UtfToExternalDString(NULL, message, -1, &messageString);
1739      Tcl_UtfToExternalDString(NULL, title, -1, &titleString);      Tcl_UtfToExternalDString(NULL, title, -1, &titleString);
1740    
1741      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);      oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
1742      winCode = MessageBox(hWnd, Tcl_DStringValue(&messageString),      winCode = MessageBox(hWnd, Tcl_DStringValue(&messageString),
1743                  Tcl_DStringValue(&titleString), flags);                  Tcl_DStringValue(&titleString), flags);
1744      (void) Tcl_SetServiceMode(oldMode);      (void) Tcl_SetServiceMode(oldMode);
1745    
1746      /*      /*
1747       * Ensure that hWnd is enabled, because it can happen that we       * Ensure that hWnd is enabled, because it can happen that we
1748       * have updated the wrapper of the parent, which causes us to       * have updated the wrapper of the parent, which causes us to
1749       * leave this child disabled (Windows loses sync).       * leave this child disabled (Windows loses sync).
1750       */       */
1751      EnableWindow(hWnd, 1);      EnableWindow(hWnd, 1);
1752    
1753      Tcl_DStringFree(&messageString);      Tcl_DStringFree(&messageString);
1754      Tcl_DStringFree(&titleString);      Tcl_DStringFree(&titleString);
1755    
1756      Tcl_SetResult(interp, TkFindStateString(buttonMap, winCode), TCL_STATIC);      Tcl_SetResult(interp, TkFindStateString(buttonMap, winCode), TCL_STATIC);
1757      return TCL_OK;      return TCL_OK;
1758  }  }
1759    
1760  static void  static void
1761  SetTkDialog(ClientData clientData)  SetTkDialog(ClientData clientData)
1762  {  {
1763      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1764              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));              Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1765      char buf[32];      char buf[32];
1766      HWND hwnd;      HWND hwnd;
1767    
1768      hwnd = (HWND) clientData;      hwnd = (HWND) clientData;
1769    
1770      sprintf(buf, "0x%08x", hwnd);      sprintf(buf, "0x%08x", hwnd);
1771      Tcl_SetVar(tsdPtr->debugInterp, "tk_dialog", buf, TCL_GLOBAL_ONLY);      Tcl_SetVar(tsdPtr->debugInterp, "tk_dialog", buf, TCL_GLOBAL_ONLY);
1772  }  }
1773    
1774  /* End of tkwindialog.c */  /* End of tkwindialog.c */

Legend:
Removed from v.70  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25