Tk Source Code

Artifact [a54a1a5e]
Login

Artifact a54a1a5e979f9e2c75a4244cf6c8adfaafc58812:

Attachment "tip242.diff" to ticket [1156388f] added by hobbs 2007-10-26 04:44:07.
? t
? tip242.diff
? doc/man.macros
? macosx/configure
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tktoolkit/tk/ChangeLog,v
retrieving revision 1.1729
diff -u -r1.1729 ChangeLog
--- ChangeLog	25 Oct 2007 16:39:23 -0000	1.1729
+++ ChangeLog	25 Oct 2007 21:41:13 -0000
@@ -1,3 +1,13 @@
+2007-10-25  Jeff Hobbs  <[email protected]>
+
+	* doc/getOpenFile.n:
+	* library/tkfbox.tcl:
+	* library/xmfbox.tcl:
+	* macosx/tkMacOSXDialog.c:
+	* tests/filebox.test:
+	* tests/winDialog.test:
+	* win/tkWinDialog.c:
+
 2007-10-25  Don Porter  <[email protected]>
 
 	* generic/tkPlace.c:    Prevent segfault in place geometry manager.
Index: doc/getOpenFile.n
===================================================================
RCS file: /cvsroot/tktoolkit/tk/doc/getOpenFile.n,v
retrieving revision 1.16
diff -u -r1.16 getOpenFile.n
--- doc/getOpenFile.n	23 Oct 2007 15:44:35 -0000	1.16
+++ doc/getOpenFile.n	25 Oct 2007 21:41:13 -0000
@@ -88,6 +88,16 @@
 \fB\-title\fR \fItitleString\fR
 Specifies a string to display as the title of the dialog box. If this
 option is not specified, then a default title is displayed. 
+.TP
+\fB\-typevariable\fR \fIvariableName\fR
+The variable \fIvariableName\fR is used to preselect which filter is
+used from \fIfilterList\fR when the dialog box is opened and is
+updated when the dialog box is closed, to the last selected
+filter. The variable is read once at the beginning to select the
+appropriate filter. If the variable does not exist, or it's value does
+not match any filter typename, or is empty (\fB{}\fR), the dialog box
+will revert to the default behavior of selecting the first filter in
+the list. If the dialog is canceled, the variable is not modified.
 .PP
 If the user selects a file, both \fBtk_getOpenFile\fR and
 \fBtk_getSaveFile\fR return the full pathname of this file. If the
Index: library/tkfbox.tcl
===================================================================
RCS file: /cvsroot/tktoolkit/tk/library/tkfbox.tcl,v
retrieving revision 1.59
diff -u -r1.59 tkfbox.tcl
--- library/tkfbox.tcl	19 Feb 2007 23:52:19 -0000	1.59
+++ library/tkfbox.tcl	25 Oct 2007 21:41:13 -0000
@@ -867,17 +867,32 @@
     $data(dirMenuBtn) configure \
 	    -textvariable ::tk::dialog::file::${dataName}(selectPath)
 
+    # Cleanup previous menu
+    #
+    $data(typeMenu) delete 0 end
+    $data(typeMenuBtn) configure -state normal -text ""
+
     # Initialize the file types menu
     #
     if {[llength $data(-filetypes)]} {
-	$data(typeMenu) delete 0 end
+	# Default type and name to first entry
+	set initialtype     [lindex $data(-filetypes) 0]
+	set initialTypeName [lindex $initialtype 0]
+	if {($data(-typevariable) ne "")
+	    && [uplevel 2 [list info exists $data(-typevariable)]]} {
+	    set initialTypeName [uplevel 2 [list set $data(-typevariable)]]
+	}
 	foreach type $data(-filetypes) {
 	    set title  [lindex $type 0]
 	    set filter [lindex $type 1]
 	    $data(typeMenu) add command -label $title \
-		    -command [list ::tk::dialog::file::SetFilter $w $type]
+		-command [list ::tk::dialog::file::SetFilter $w $type]
+	    # string first avoids glob-pattern char issues
+	    if {[string first ${initialTypeName} $title] == 0} {
+		set initialtype $type
+	    }
 	}
-	SetFilter $w [lindex $data(-filetypes) 0]
+	SetFilter $w $initialtype
 	$data(typeMenuBtn) configure -state normal
 	$data(typeMenuLab) configure -state normal
     } else {
@@ -949,6 +964,7 @@
 	{-initialfile "" "" ""}
 	{-parent "" "" "."}
 	{-title "" "" ""}
+	{-typevariable "" "" ""}
     }
 
     # The "-multiple" option is only available for the "open" file dialog.
@@ -1383,6 +1399,7 @@
     upvar ::tk::dialog::file::[winfo name $w] data
     upvar ::tk::$data(icons) icons
 
+    set data(filterType) $type
     set data(filter) [lindex $type 1]
     $data(typeMenuBtn) configure -text [lindex $type 0] -indicatoron 1
 
@@ -1838,6 +1855,12 @@
 		return
 	    }
 	}
+	if {[info exists data(-typevariable)] && $data(-typevariable) ne ""
+	    && [info exists data(-filetypes)] && [llength $data(-filetypes)]
+	    && [info exists data(filterType)] && $data(filterType) ne ""} {
+	    upvar 4 $data(-typevariable) initialTypeName
+	    set initialTypeName [lindex $data(filterType) 0]
+	}
     }
     bind $data(okBtn) <Destroy> {}
     set Priv(selectFilePath) $selectFilePath
Index: library/xmfbox.tcl
===================================================================
RCS file: /cvsroot/tktoolkit/tk/library/xmfbox.tcl,v
retrieving revision 1.29
diff -u -r1.29 xmfbox.tcl
--- library/xmfbox.tcl	17 Mar 2006 11:13:15 -0000	1.29
+++ library/xmfbox.tcl	25 Oct 2007 21:41:13 -0000
@@ -157,7 +157,22 @@
 
     # The filetypes radiobuttons
     # set data(fileType) $data(-defaulttype)
+    # Default type to first entry
+    set initialTypeName [lindex $data(-filetypes) 0 0]
+    if {($data(-typevariable) ne "")
+	&& [uplevel 4 [list info exists $data(-typevariable)]]} {
+	set initialTypeName [uplevel 4 [list set $data(-typevariable)]]
+    }
+    set ix 0
     set data(fileType) 0
+    foreach fltr $data(-filetypes) {
+	set fname [lindex $fltr 0]
+	if {[string first $initialTypeName $fname] == 0} {
+	    set data(fileType) $ix
+	    break
+	}
+	incr ix
+    }
 
     MotifFDialog_SetFilter $w [lindex $data(-filetypes) $data(fileType)]
 
@@ -176,7 +191,7 @@
 		-text $title \
 		-variable ::tk::dialog::file::[winfo name $w](fileType) \
 		-value $cnt \
-		-command "[list tk::MotifFDialog_SetFilter $w $type]"
+		-command [list tk::MotifFDialog_SetFilter $w $type]
 	    pack $f.b$cnt -side left
 	    incr cnt
 	}
@@ -226,6 +241,7 @@
 	{-initialfile "" "" ""}
 	{-parent "" "" "."}
 	{-title "" "" ""}
+	{-typevariable "" "" ""}
     }
     if {$type eq "open"} {
 	lappend specs {-multiple "" "" "0"}
@@ -841,10 +857,17 @@
 		return
 	    }
 	}
-	
+
 	lappend newFileList $item
     }
 
+    # Return selected filter
+    if {[info exists data(-typevariable)] && $data(-typevariable) ne ""
+	&& [info exists data(-filetypes)] && $data(-filetypes) ne ""} {
+	upvar 2 $data(-typevariable) initialTypeName
+	set initialTypeName [lindex $data(-filetypes) $data(fileType) 0]
+    }
+
     if {$data(-multiple) != 0} {
 	set Priv(selectFilePath) $newFileList
     } else {
Index: macosx/tkMacOSXDialog.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/macosx/tkMacOSXDialog.c,v
retrieving revision 1.30
diff -u -r1.30 tkMacOSXDialog.c
--- macosx/tkMacOSXDialog.c	11 Sep 2007 05:24:13 -0000	1.30
+++ macosx/tkMacOSXDialog.c	25 Oct 2007 21:41:13 -0000
@@ -38,14 +38,14 @@
  * The following structures are used in the GetFileName() function. They store
  * information about the file dialog and the file filters.
  */
-
-typedef struct OpenFileData {
-    FileFilterList fl;		/* List of file filters. */
-    SInt16 curType;		/* The filetype currently being listed. */
-    short popupItem;		/* Item number of the popup in the dialog. */
-    int usePopup;		/* True if we show the popup menu (this is
-				 * an open operation and the -filetypes
-				 * option is set). */
+typedef struct _OpenFileData {
+    FileFilterList fl;          /* List of file filters.                   */
+    SInt16 curType;             /* The filetype currently being listed.    */
+    short initialType;          /* Type to use initially                   */
+    short popupItem;            /* Item number of the popup in the dialog. */
+    short usePopup;             /* True if we show the popup menu (this    */
+                                /* is an open operation and the            */
+                                /* -filetypes option is set).              */
 } OpenFileData;
 
 typedef struct NavHandlerUserData {
@@ -85,7 +85,8 @@
 			    OpenFileData *ofd, AEDesc *initialDescPtr,
 			    char *initialFile, AEDescList *selectDescPtr,
 			    CFStringRef title, CFStringRef message,
-			    int multiple, int isOpen, Tk_Window parent);
+			    const char *initialType, int multiple, int isOpen, 
+			    Tk_Window parent);
 static int		HandleInitialDirectory(Tcl_Interp *interp,
 			    char *initialFile, char *initialDir, FSRef *dirRef,
 			    AEDescList *selectDescPtr, AEDesc *dirDescPtr);
@@ -261,22 +262,25 @@
     AEDesc *initialPtr = NULL;
     AEDescList selectDesc = {typeNull, NULL};
     char *initialFile = NULL, *initialDir = NULL;
+    Tcl_Obj *typeVariablePtr = NULL;
+    const char *initialtype = NULL;
     static const char *openOptionStrings[] = {
 	"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
-	"-message", "-multiple", "-parent", "-title", NULL
+	"-message", "-multiple", "-parent", "-title", "-typevariable", NULL
     };
     enum openOptions {
 	OPEN_DEFAULT, OPEN_FILETYPES, OPEN_INITDIR, OPEN_INITFILE,
-	OPEN_MESSAGE, OPEN_MULTIPLE, OPEN_PARENT, OPEN_TITLE
+	OPEN_MESSAGE, OPEN_MULTIPLE, OPEN_PARENT, OPEN_TITLE, OPEN_TYPEVARIABLE
     };
 
     if (!fileDlgInited) {
 	InitFileDialogs();
     }
     TkInitFileFilters(&ofd.fl);
-    ofd.curType = 0;
-    ofd.popupItem = OPEN_POPUP_ITEM;
-    ofd.usePopup = 1;
+    ofd.curType          = 0;
+    ofd.initialType      = -1;
+    ofd.popupItem        = OPEN_POPUP_ITEM;
+    ofd.usePopup         = 1;
 
     for (i = 1; i < objc; i += 2) {
 	char *choice;
@@ -338,6 +342,9 @@
 		title = CFStringCreateWithBytes(NULL, (unsigned char*)
 			choice, choiceLen, kCFStringEncodingUTF8, false);
 		break;
+	    case OPEN_TYPEVARIABLE:
+	        typeVariablePtr = objv[i + 1];
+	        break;
 	}
     }
 
@@ -349,8 +356,23 @@
     if (initialDesc.descriptorType == typeFSRef) {
 	initialPtr = &initialDesc;
     }
-    result = NavServicesGetFile(interp, &ofd, initialPtr, NULL, &selectDesc,
-	    title, message, multiple, OPEN_FILE, parent);
+
+    if (typeVariablePtr) {
+	initialtype = Tcl_GetVar(interp, Tcl_GetString(typeVariablePtr), 0);
+    }
+    result = NavServicesGetFile(interp, &ofd, initialPtr, NULL, &selectDesc, 
+	    title, message, initialtype, multiple, OPEN_FILE, parent);
+
+    if (typeVariablePtr) {
+	int i = ofd.curType;
+	FileFilter *filterPtr;
+	for (filterPtr = ofd.fl.filters; 
+	     filterPtr && i > 0; i--) {
+	    filterPtr = filterPtr->next;
+	}
+	Tcl_SetVar(interp, Tcl_GetString(typeVariablePtr), filterPtr->name, 0);
+    }
+
 end:
     TkFreeFileFilters(&ofd.fl);
     if (initialDesc.dataHandle) {
@@ -401,11 +423,11 @@
     OpenFileData ofd;
     static const char *saveOptionStrings[] = {
 	"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
-	"-message", "-parent", "-title", NULL
+	"-message", "-parent", "-title", "-typevariable", NULL
     };
     enum saveOptions {
 	SAVE_DEFAULT, SAVE_FILETYPES, SAVE_INITDIR, SAVE_INITFILE,
-	SAVE_MESSAGE, SAVE_PARENT, SAVE_TITLE
+	SAVE_MESSAGE, SAVE_PARENT, SAVE_TITLE, SAVE_TYPEVARIABLE
     };
 
     if (!fileDlgInited) {
@@ -480,7 +502,7 @@
 	initialPtr = &initialDesc;
     }
     result = NavServicesGetFile(interp, &ofd, initialPtr, initialFile, NULL,
-	    title, message, false, SAVE_FILE, parent);
+	    title, message, NULL, false, SAVE_FILE, parent);
     TkFreeFileFilters(&ofd.fl);
 end:
     if (initialDesc.dataHandle) {
@@ -588,7 +610,7 @@
 	initialPtr = &initialDesc;
     }
     result = NavServicesGetFile(interp, &ofd, initialPtr, NULL, NULL, title,
-	    message, false, CHOOSE_FOLDER, parent);
+	    message, NULL, false, CHOOSE_FOLDER, parent);
     TkFreeFileFilters(&ofd.fl);
 end:
     if (initialDesc.dataHandle) {
@@ -737,6 +759,7 @@
     AEDescList *selectDescPtr,
     CFStringRef title,
     CFStringRef message,
+    const char *initialtype,
     int multiple,
     int isOpen,
     Tk_Window parent)
@@ -800,6 +823,9 @@
 		filterPtr = filterPtr->next, index++) {
 	    menuItemNames[index] = CFStringCreateWithCString(NULL,
 		    filterPtr->name, kCFStringEncodingUTF8);
+	    if (initialtype && strcmp(filterPtr->name, initialtype) == 0) {
+		ofdPtr->initialType = index;
+	    }
 	}
 	options.popupExtension = CFArrayCreate(NULL,
 		(const void **) menuItemNames, ofdPtr->fl.numFilters, NULL);
@@ -988,8 +1014,33 @@
     NavCallBackUserData callBackUD)
 {
     NavHandlerUserData *data = (NavHandlerUserData*) callBackUD;
-
+    OpenFileData *ofd = data->ofdPtr;
     switch (callBackSelector) {
+	case kNavCBStart:
+	  if (ofd && ofd->initialType >= 0) {
+		  /* Select initial filter */
+		  int i = ofd->initialType;
+		  FileFilter *filterPtr;
+
+		  for (filterPtr = ofd->fl.filters; 
+			   filterPtr && i > 0; i--) {
+			  filterPtr = filterPtr->next;
+		  }
+		  if (filterPtr) {
+			  NavMenuItemSpec selectItem;
+			  OSStatus err;
+			  selectItem.version = kNavMenuItemSpecVersion;
+			  selectItem.menuCreator = 0;
+			  selectItem.menuType = ofd->initialType;
+			  selectItem.menuItemName[0] = strlen(filterPtr->name);
+			  strncpy(&selectItem.menuItemName[1], filterPtr->name, 255);
+			  err = NavCustomControl(callBackParams->context, kNavCtlSelectCustomType, &selectItem);
+			  if (err != noErr) {
+				  fprintf(stderr,"NavCustomControl kNavCtlSelectCustomType Failed, %d\n", (int)err );
+			  }
+		  }
+	  }
+	  break;
 	case kNavCBPopupMenuSelect:
 	    data->ofdPtr->curType = ((NavMenuItemSpec *)
 		    callBackParams->eventData.eventDataParms.param)->menuType;
@@ -1077,7 +1128,7 @@
 			fileName[len] = '\0';
 			fileNamePtr = (unsigned char*) fileName;
 
-		    } else if ((theItem->descriptorType = typeFSRef)) {
+		    } else if ((theItem->descriptorType == typeFSRef)) {
 			OSStatus err;
 			FSRef *theRef = (FSRef *) *theItem->dataHandle;
 			HFSUniStr255 uniFileName;
Index: tests/filebox.test
===================================================================
RCS file: /cvsroot/tktoolkit/tk/tests/filebox.test,v
retrieving revision 1.18
diff -u -r1.18 filebox.test
--- tests/filebox.test	20 Dec 2004 10:34:20 -0000	1.18
+++ tests/filebox.test	25 Oct 2007 21:41:13 -0000
@@ -113,8 +113,8 @@
     set modes 1
 }
 
-set unknownOptionsMsg(tk_getOpenFile) {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, or -title}
-set unknownOptionsMsg(tk_getSaveFile) {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -parent, or -title}
+set unknownOptionsMsg(tk_getOpenFile) {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, -title, or -typevariable}
+set unknownOptionsMsg(tk_getSaveFile) {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -parent, -title, or -typevariable}
 
 set tmpFile "filebox.tmp"
 makeFile {
@@ -269,6 +269,27 @@
 		    -initialfile $fileName -initialdir $fileDir]
         } $pathName
     }
+    foreach {x res} [list 1 "-unset-" 2 "Text files"] {
+	set t [expr {$x + [llength [array names filters]]}]
+        test filebox-3.$t-$mode "tk_getOpenFile command" nonUnixUserInteraction {
+	    catch {unset tv}
+	    catch {unset typeName}
+	    ToPressButton $parent ok
+	    if {[info exists tv]} {
+	    } else {
+	    }
+	    set choice [tk_getOpenFile -title "Press Ok" \
+		    -filetypes $filters($x) -parent $parent \
+		    -initialfile $fileName -initialdir $fileDir \
+		    -typevariable tv]
+	    if {[info exists tv]} {
+		regexp {^(.*) \(.*\)$} $tv dummy typeName
+	    } else {
+		set typeName "-unset-"
+	    }
+	    set typeName
+        } $res
+    }
 
     test filebox-4.1-$mode "tk_getSaveFile command" -body {
 	tk_getSaveFile -foo
Index: tests/winDialog.test
===================================================================
RCS file: /cvsroot/tktoolkit/tk/tests/winDialog.test,v
retrieving revision 1.13
diff -u -r1.13 winDialog.test
--- tests/winDialog.test	17 Oct 2006 10:21:50 -0000	1.13
+++ tests/winDialog.test	25 Oct 2007 21:41:13 -0000
@@ -89,7 +89,7 @@
 } {0}
 test winDialog-5.2 {GetFileName: one argument} {nt} {
     list [catch {tk_getOpenFile -foo} msg] $msg
-} {1 {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, or -title}}
+} {1 {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, -title, or -typevariable}}
 test winDialog-5.4 {GetFileName: many arguments} {nt testwinevent} {
     start {tk_getOpenFile -initialdir c:/ -parent . -title test -initialfile foo}
     then {
@@ -98,7 +98,7 @@
 } {0}
 test winDialog-5.5 {GetFileName: Tcl_GetIndexFromObj() != TCL_OK} {nt} {
     list [catch {tk_getOpenFile -foo bar -abc} msg] $msg
-} {1 {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, or -title}}
+} {1 {bad option "-foo": must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, -title, or -typevariable}}
 test winDialog-5.6 {GetFileName: Tcl_GetIndexFromObj() == TCL_OK} {nt testwinevent} {
     start {tk_getOpenFile -title bar}
     then {
Index: win/tkWinDialog.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/win/tkWinDialog.c,v
retrieving revision 1.46
diff -u -r1.46 tkWinDialog.c
--- win/tkWinDialog.c	8 Sep 2007 16:13:45 -0000	1.46
+++ win/tkWinDialog.c	25 Oct 2007 21:41:13 -0000
@@ -189,7 +189,8 @@
 			    Tcl_Interp *interp, int objc,
 			    Tcl_Obj *CONST objv[], int isOpen);
 static int 		MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr,
-			    Tcl_DString *dsPtr);
+			    Tcl_DString *dsPtr, Tcl_Obj *initialPtr,
+			    int *index);
 static UINT APIENTRY	OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam,
 			    LPARAM lParam);
 static UINT APIENTRY	OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam,
@@ -575,10 +576,11 @@
 {
     OPENFILENAMEW ofn;
     WCHAR file[TK_MULTI_MAX_PATH];
-    int result, winCode, oldMode, i, multi = 0;
+    int filterIndex, result, winCode, oldMode, i, multi = 0;
     char *extension, *filter, *title;
     Tk_Window tkwin;
     HWND hWnd;
+    Tcl_Obj *filterObj, *initialTypeObj, *typeVariableObj;
     Tcl_DString utfFilterString, utfDirString;
     Tcl_DString extString, filterString, dirString, titleString;
     Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding();
@@ -586,17 +588,17 @@
 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
     static CONST char *saveOptionStrings[] = {
 	"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
-	"-parent", "-title", NULL
+	"-parent", "-title", "-typevariable", NULL
     };
     static CONST char *openOptionStrings[] = {
 	"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
-	"-multiple", "-parent", "-title", NULL
+	"-multiple", "-parent", "-title", "-typevariable", NULL
     };
     CONST char **optionStrings;
 
     enum options {
 	FILE_DEFAULT,	FILE_TYPES,	FILE_INITDIR,	FILE_INITFILE,
-	FILE_MULTIPLE,	FILE_PARENT,	FILE_TITLE
+	FILE_MULTIPLE,	FILE_PARENT,	FILE_TITLE,     FILE_TYPEVARIABLE
     };
 
     result = TCL_ERROR;
@@ -612,6 +614,9 @@
     Tcl_DStringInit(&utfDirString);
     tkwin = (Tk_Window) clientData;
     title = NULL;
+    filterObj = NULL;
+    typeVariableObj = NULL;
+    initialTypeObj = NULL;
 
     if (open) {
 	optionStrings = openOptionStrings;
@@ -663,11 +668,7 @@
 	    extension = string;
 	    break;
 	case FILE_TYPES:
-	    Tcl_DStringFree(&utfFilterString);
-	    if (MakeFilter(interp, valuePtr, &utfFilterString) != TCL_OK) {
-		goto end;
-	    }
-	    filter = Tcl_DStringValue(&utfFilterString);
+	    filterObj = valuePtr;
 	    break;
 	case FILE_INITDIR:
 	    Tcl_DStringFree(&utfDirString);
@@ -702,14 +703,18 @@
 	case FILE_TITLE:
 	    title = string;
 	    break;
+	case FILE_TYPEVARIABLE:
+	    typeVariableObj = valuePtr;
+	    initialTypeObj = Tcl_ObjGetVar2(interp, typeVariableObj, NULL, 0);
+	    break;
 	}
     }
 
-    if (filter == NULL) {
-	if (MakeFilter(interp, NULL, &utfFilterString) != TCL_OK) {
-	    goto end;
-	}
+    if (MakeFilter(interp, filterObj, &utfFilterString, initialTypeObj,
+		    &filterIndex) != TCL_OK) {
+	goto end;
     }
+    filter = Tcl_DStringValue(&utfFilterString);
 
     Tk_MakeWindowExist(tkwin);
     hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
@@ -748,6 +753,7 @@
 	    Tcl_DStringValue(&utfFilterString),
 	    Tcl_DStringLength(&utfFilterString), &filterString);
     ofn.lpstrFilter = (WCHAR *) Tcl_DStringValue(&filterString);
+    ofn.nFilterIndex = filterIndex;
 
     if (Tcl_DStringValue(&utfDirString)[0] != '\0') {
 	Tcl_UtfToExternalDString(unicodeEncoding,
@@ -878,6 +884,23 @@
 		    (char *) ofn.lpstrFile, &ds), NULL);
 	    Tcl_DStringFree(&ds);
 	}
+	if ((ofn.nFilterIndex > 0) &&
+		Tcl_GetCharLength(Tcl_GetObjResult(interp)) > 0 &&
+		typeVariableObj && filterObj) {
+	    int listObjc, count;
+	    Tcl_Obj **listObjv = NULL;
+	    Tcl_Obj **typeInfo = NULL;
+	    if (Tcl_ListObjGetElements(interp, filterObj,
+			    &listObjc, &listObjv) != TCL_OK) {
+		result = TCL_ERROR;
+	    } else if (Tcl_ListObjGetElements(interp,
+			    listObjv[ofn.nFilterIndex - 1],
+			    &count, &typeInfo) != TCL_OK) {
+		result = TCL_ERROR;
+	    } else {
+		Tcl_ObjSetVar2(interp, typeVariableObj, NULL, typeInfo[0], 0);
+	    }
+	}
 	result = TCL_OK;
     } else {
 	/*
@@ -997,27 +1020,28 @@
 {
     OPENFILENAME ofn;
     TCHAR file[TK_MULTI_MAX_PATH], savePath[MAX_PATH];
-    int result, winCode, oldMode, i, multi = 0;
+    int filterIndex, result, winCode, oldMode, i, multi = 0;
     char *extension, *filter, *title;
     Tk_Window tkwin;
     HWND hWnd;
+    Tcl_Obj *filterObj, *initialTypeObj, *typeVariableObj;
     Tcl_DString utfFilterString, utfDirString;
     Tcl_DString extString, filterString, dirString, titleString;
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
     static CONST char *saveOptionStrings[] = {
 	"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
-	"-parent", "-title", NULL
+	"-parent", "-title", "-typevariable", NULL
     };
     static CONST char *openOptionStrings[] = {
 	"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
-	"-multiple", "-parent", "-title", NULL
+	"-multiple", "-parent", "-title", "-typevariable", NULL
     };
     CONST char **optionStrings;
 
     enum options {
 	FILE_DEFAULT,	FILE_TYPES,	FILE_INITDIR,	FILE_INITFILE,
-	FILE_MULTIPLE,	FILE_PARENT,	FILE_TITLE
+	FILE_MULTIPLE,	FILE_PARENT,	FILE_TITLE, FILE_TYPEVARIABLE
     };
 
     result = TCL_ERROR;
@@ -1033,6 +1057,9 @@
     Tcl_DStringInit(&utfDirString);
     tkwin = (Tk_Window) clientData;
     title = NULL;
+    filterObj = NULL;
+    typeVariableObj = NULL;
+    initialTypeObj = NULL;
 
     if (open) {
 	optionStrings = openOptionStrings;
@@ -1084,11 +1111,7 @@
 	    extension = string;
 	    break;
 	case FILE_TYPES:
-	    Tcl_DStringFree(&utfFilterString);
-	    if (MakeFilter(interp, valuePtr, &utfFilterString) != TCL_OK) {
-		goto end;
-	    }
-	    filter = Tcl_DStringValue(&utfFilterString);
+	    filterObj = valuePtr;
 	    break;
 	case FILE_INITDIR:
 	    Tcl_DStringFree(&utfDirString);
@@ -1122,14 +1145,18 @@
 	case FILE_TITLE:
 	    title = string;
 	    break;
+	case FILE_TYPEVARIABLE:
+	    typeVariableObj = valuePtr;
+	    initialTypeObj = Tcl_ObjGetVar2(interp, typeVariableObj, NULL, 0);
+	    break;
 	}
     }
 
-    if (filter == NULL) {
-	if (MakeFilter(interp, NULL, &utfFilterString) != TCL_OK) {
-	    goto end;
-	}
+    if (MakeFilter(interp, filterObj, &utfFilterString, initialTypeObj,
+		    &filterIndex) != TCL_OK) {
+	goto end;
     }
+    filter = Tcl_DStringValue(&utfFilterString);
 
     Tk_MakeWindowExist(tkwin);
     hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
@@ -1306,6 +1333,23 @@
 		    (char *) ofn.lpstrFile, &ds), NULL);
 	    Tcl_DStringFree(&ds);
 	}
+	if ((ofn.nFilterIndex > 0) &&
+		(Tcl_GetCharLength(Tcl_GetObjResult(interp)) > 0) &&
+		typeVariableObj && filterObj) {
+	    int listObjc, count;
+	    Tcl_Obj **listObjv = NULL;
+	    Tcl_Obj **typeInfo = NULL;
+	    if (Tcl_ListObjGetElements(interp, filterObj,
+			    &listObjc, &listObjv) != TCL_OK) {
+		result = TCL_ERROR;
+	    } else if (Tcl_ListObjGetElements(interp,
+			    listObjv[ofn.nFilterIndex - 1],
+			    &count, &typeInfo) != TCL_OK) {
+		result = TCL_ERROR;
+	    } else {
+		Tcl_ObjSetVar2(interp, typeVariableObj, NULL, typeInfo[0], 0);
+	    }
+	}
 	result = TCL_OK;
     } else {
 	/*
@@ -1422,14 +1466,21 @@
 MakeFilter(
     Tcl_Interp *interp,		/* Current interpreter. */
     Tcl_Obj *valuePtr,		/* Value of the -filetypes option */
-    Tcl_DString *dsPtr)		/* Filled with windows filter string. */
+    Tcl_DString *dsPtr,		/* Filled with windows filter string. */
+    Tcl_Obj *initialPtr,	/* Initial type name  */
+    int *index)			/* Index of initial type in filter string */
 {
     char *filterStr;
     char *p;
+    char *initial = NULL;
     int pass;
+    int ix = 0; /* index counter */
     FileFilterList flist;
     FileFilter *filterPtr;
 
+    if (initialPtr) {
+	initial = Tcl_GetStringFromObj(initialPtr, NULL);
+    }
     TkInitFileFilters(&flist);
     if (TkGetFileFilters(interp, &flist, valuePtr, 1) != TCL_OK) {
 	return TCL_ERROR;
@@ -1485,6 +1536,15 @@
 	    FileFilterClause *clausePtr;
 
 	    /*
+	     * Check initial index for match, set index.
+	     * Filter index is 1 based so increment first
+	     */
+	    ix++;
+	    if (index && initial && (strcmp(initial, filterPtr->name) == 0)) {
+		*index = ix;
+	    }
+
+	    /*
 	     * First, put in the name of the file type.
 	     */