diff --git a/cocoa/dlg.go b/cocoa/dlg.go
index 7488bd2743f86ccd6ce65bff3ee7d0833113348c..b6fe7bdb8b1972237a3ca99edf76d4b8a3685223 100644
--- a/cocoa/dlg.go
+++ b/cocoa/dlg.go
@@ -59,9 +59,21 @@ func ErrorDlg(msg, title string) {
 
 const BUFSIZE = C.PATH_MAX
 
-func FileDlg(save int, title string, exts []string, relaxExt bool) (string, error) {
+func FileDlg(save bool, title string, exts []string, relaxExt bool) (string, error) {
+	mode := C.LOADDLG
+	if save {
+		mode = C.SAVEDLG
+	}
+	return fileDlg(mode, title, exts, relaxExt)
+}
+
+func DirDlg(title string) (string, error) {
+	return fileDlg(C.DIRDLG, title, nil, false)
+}
+
+func fileDlg(mode int, title string, exts []string, relaxExt bool) (string, error) {
 	p := C.FileDlgParams{
-		save: C.int(save),
+		mode: C.int(mode),
 		nbuf: BUFSIZE,
 	}
 	p.buf = (*C.char)(C.malloc(BUFSIZE))
diff --git a/cocoa/dlg.h b/cocoa/dlg.h
index 3764f87ba6ffefea7c4fc865e4daef59198d39a5..2890a9fa5c3a95c533a4b300c406897046ab47ac 100644
--- a/cocoa/dlg.h
+++ b/cocoa/dlg.h
@@ -12,8 +12,12 @@ typedef struct {
 	AlertStyle style;
 } AlertDlgParams;
 
+#define LOADDLG 0
+#define SAVEDLG 1
+#define DIRDLG 2 // browse for directory
+
 typedef struct {
-	int save; /* non-zero => save dialog, zero => open dialog */
+	int mode; /* which dialog style to invoke (see earlier defines) */
 	char* buf; /* buffer to store selected file */
 	int nbuf; /* number of bytes allocated at buf */
 	char* title; /* title for dialog box (can be nil) */
diff --git a/cocoa/dlg.m b/cocoa/dlg.m
index 3348c3b3d24cc5b6f3c9cbb9f25f45708362ee4b..2963619d0b8df8394b123caafb3893c19794790c 100644
--- a/cocoa/dlg.m
+++ b/cocoa/dlg.m
@@ -79,7 +79,7 @@ DlgResult fileDlg(FileDlgParams* params) {
 - (DlgResult)run {
 	if(![NSThread isMainThread]) {
 		[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
-	} else if(self->params->save) {
+	} else if(self->params->mode == SAVEDLG) {
 		self->result = [self save];
 	} else {
 		self->result = [self load];
@@ -113,6 +113,10 @@ DlgResult fileDlg(FileDlgParams* params) {
 
 - (DlgResult)load {
 	NSOpenPanel* panel = [NSOpenPanel openPanel];
+	if(self->params->mode == DIRDLG) {
+		[panel setCanChooseDirectories:YES];
+		[panel setCanChooseFiles:NO];
+	}
 	if(![self runPanel:panel]) {
 		return DLG_CANCEL;
 	}
@@ -122,4 +126,5 @@ DlgResult fileDlg(FileDlgParams* params) {
 	}
 	return DLG_OK;
 }
+
 @end
\ No newline at end of file
diff --git a/dlgs_darwin.go b/dlgs_darwin.go
index adda6fe81719740934e441d1485a925d8fc5ce60..ae28560a0194baf8bb21b6d1105a7bfc868c31ea 100644
--- a/dlgs_darwin.go
+++ b/dlgs_darwin.go
@@ -17,14 +17,14 @@ func (b *MsgBuilder) error() {
 }
 
 func (b *FileBuilder) load() (string, error) {
-	return b.run(0)
+	return b.run(false)
 }
 
 func (b *FileBuilder) save() (string, error) {
-	return b.run(1)
+	return b.run(true)
 }
 
-func (b *FileBuilder) run(save int) (string, error) {
+func (b *FileBuilder) run(save bool) (string, error) {
 	star := false
 	var exts []string
 	for _, filt := range b.Filters {
@@ -36,7 +36,7 @@ func (b *FileBuilder) run(save int) (string, error) {
 			}
 		}
 	}
-	if star && save == 0 {
+	if star && save {
 		/* OSX doesn't allow the user to switch visible file types/extensions. Also
 		** NSSavePanel's allowsOtherFileTypes property has no effect for an open
 		** dialog, so if "*" is a possible extension we must always show all files. */
@@ -50,5 +50,9 @@ func (b *FileBuilder) run(save int) (string, error) {
 }
 
 func (b *DirectoryBuilder) browse() (string, error) {
-	panic("not implemented")
+	f, err := cocoa.DirDlg(b.Dlg.Title);
+	if f == "" && err == nil {
+		return "", Cancelled
+	}
+	return f, err
 }