diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index 501e9119fbb0c843f059bff6ca44a2ea42cf1da9..86c9e8fdc60c659b476311ac418ba198e340f1c0 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -2005,20 +2005,16 @@ void LLWindowSDL::gatherInput()
 			SDLReallyCaptureInput(TRUE);
 
                 if (event.key.keysym.unicode)
-				{
-					handleUnicodeUTF16(event.key.keysym.unicode,
-									   gKeyboard->currentMask(FALSE));
-				}
+		{
+			handleUnicodeUTF16(event.key.keysym.unicode,
+					   gKeyboard->currentMask(FALSE));
+		}
                 break;
 
             case SDL_KEYUP:
 		if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0)
 			SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243
 
-		// This is a testing hack to pop up a dialog when 4 is pressed
-		//if (event.key.keysym.sym == SDLK_4)
-		//OSMessageBox("a whole bunch of text goes right here, whee!  test test test.", "this is the title!", OSMB_YESNO);
-
 		gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod);
                 break;
 
@@ -2099,9 +2095,9 @@ void LLWindowSDL::gatherInput()
                 else if (event.button.button == SDL_BUTTON_RIGHT)  // right ... yes, it's 3, not 2, in SDL...
 				    mCallbacks->handleRightMouseUp(this, openGlCoord, mask);
                 else if (event.button.button == SDL_BUTTON_MIDDLE)  // middle
-				{
-					mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask);
-				}
+		{
+			mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask);
+		}
                 // don't handle mousewheel here...
 
                 break;
@@ -2155,18 +2151,18 @@ void LLWindowSDL::gatherInput()
                 }
                 if (event.active.state & SDL_APPACTIVE)
                 {
-					// Change in iconification/minimization state.
-					if ((!event.active.gain) != mIsMinimized)
-					{
-						mCallbacks->handleActivate(this, !!event.active.gain);
-						llinfos << "SDL deiconification state switched to " << BOOL(event.active.gain) << llendl;
-			
-						mIsMinimized = (!event.active.gain);
-					}
-					else
-					{
-						llinfos << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << llendl;
-					}
+			// Change in iconification/minimization state.
+			if ((!event.active.gain) != mIsMinimized)
+			{
+				mCallbacks->handleActivate(this, !!event.active.gain);
+				llinfos << "SDL deiconification state switched to " << BOOL(event.active.gain) << llendl;
+	
+				mIsMinimized = (!event.active.gain);
+			}
+			else
+			{
+				llinfos << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << llendl;
+			}
                 }
                 break;
 
diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp
index 178cfb4e61938b8284af2d337fd4f88d17985af8..54b815e3a4ee4b82da96ae89436c26533df38346 100644
--- a/indra/newview/lldirpicker.cpp
+++ b/indra/newview/lldirpicker.cpp
@@ -17,6 +17,10 @@
 #include "lldir.h"
 #include "llframetimer.h"
 
+#if LL_LINUX
+# include "llfilepicker.h"
+#endif
+
 //
 // Globals
 //
@@ -237,6 +241,56 @@ void LLDirPicker::reset()
 	mDir    = NULL;
 }
 
+#elif LL_LINUX
+
+LLDirPicker::LLDirPicker() 
+{
+	mFilePicker = new LLFilePicker();
+	reset();
+}
+
+LLDirPicker::~LLDirPicker()
+{
+	delete mFilePicker;
+}
+
+
+void LLDirPicker::reset()
+{
+	if (mFilePicker)
+		mFilePicker->reset();
+}
+
+BOOL LLDirPicker::getDir(LLString* filename)
+{
+	reset();
+	if (mFilePicker)
+	{
+		GtkWindow* picker = mFilePicker->buildFilePicker(false, true,
+								 "dirpicker");
+
+		if (picker)
+		{		   
+		   gtk_window_set_title(GTK_WINDOW(picker), "Choose Directory");
+		   gtk_widget_show_all(GTK_WIDGET(picker));
+		   gtk_main();
+		   return (NULL != mFilePicker->getFirstFile());
+		}
+	}
+	return FALSE;
+}
+
+LLString LLDirPicker::getDirName()
+{
+	if (mFilePicker)
+	{
+		const char* name = mFilePicker->getFirstFile();
+		if (name)
+			return name;
+	}
+	return "";
+}
+
 #else // not implemented
 
 LLDirPicker::LLDirPicker() 
diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h
index 7a80d047e12c9adc03374b81980ea2b808f90fe8..062e368d06bc923a0f4013c06dfdee61ff9af912 100644
--- a/indra/newview/lldirpicker.h
+++ b/indra/newview/lldirpicker.h
@@ -33,6 +33,8 @@
 #include <commdlg.h>
 #endif
 
+class LLFilePicker;
+
 class LLDirPicker
 {
 public:
@@ -64,6 +66,11 @@ class LLDirPicker
 	
 #endif
 
+#if LL_LINUX
+	// On Linux we just implement LLDirPicker on top of LLFilePicker
+	LLFilePicker *mFilePicker;
+#endif
+
 	char mDirs[DIRNAME_BUFFER_SIZE]; /*Flawfinder: ignore*/
 	LLString* mFileName;
 	LLString  mDir;
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 51e918e1d5172cbbf96c61099ed7aed5ff04b1e9..174e3b238117f4f6940f8dd3855edc95c28c8835 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -9,8 +9,6 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llfilepicker.h"
-//#include "viewer.h"
-//#include "llviewermessage.h"
 #include "llworld.h"
 #include "llviewerwindow.h"
 #include "llkeyboard.h"
@@ -937,6 +935,10 @@ void LLFilePicker::reset()
 #elif LL_LINUX
 
 # if LL_GTK
+// This caches the previously-accessed path for a given context of the file
+// chooser, for user convenience.
+std::map <std::string, std::string> LLFilePicker::sContextToPathMap;
+
 LLFilePicker::LLFilePicker() 
 {
 	reset();
@@ -946,51 +948,83 @@ LLFilePicker::~LLFilePicker()
 {
 }
 
-static void store_filenames(GtkWidget *widget, gpointer user_data) {
+
+static void add_to_sfs(gpointer data, gpointer user_data)
+{
 	StoreFilenamesStruct *sfs = (StoreFilenamesStruct*) user_data;
-	GtkWidget *win = sfs->win;
+	gchar* filename_utf8 = g_filename_to_utf8((gchar*)data,
+						  -1, NULL,
+						  NULL,
+						  NULL);
+	sfs->fileVector.push_back(LLString(filename_utf8));
+	g_free(filename_utf8);
+}
 
-	llinfos <<"store_filesnames: marker A" << llendl;
 
-	// get NULL-terminated list of strings allocated for us by GTK
-	gchar** string_list =
-		gtk_file_selection_get_selections(GTK_FILE_SELECTION(win));
+void chooser_responder(GtkWidget *widget,
+		       gint       response,
+		       gpointer user_data) {
+	StoreFilenamesStruct *sfs = (StoreFilenamesStruct*) user_data;
 
-	llinfos <<"store_filesnames: marker B" << llendl;
+	lldebugs << "GTK DIALOG RESPONSE " << response << llendl;
 
-	int idx = 0;
-	while (string_list[idx])
+	if (response == GTK_RESPONSE_ACCEPT)
 	{
-		// platform-string to utf8
-		gchar* filename_utf8 = g_filename_from_utf8(string_list[idx],
-							    -1, NULL,
-							    NULL,
-							    NULL);
-		sfs->fileVector.push_back(LLString(filename_utf8));
-		++idx;
+		GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
+		g_slist_foreach(file_list, (GFunc)add_to_sfs, sfs);
+		g_slist_foreach(file_list, (GFunc)g_free, NULL);
+		g_slist_free (file_list);
 	}
 
-	llinfos <<"store_filesnames: marker C" << llendl;
+	// set the default path for this usage context.
+	LLFilePicker::sContextToPathMap[sfs->contextName] =
+		gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
 
-	g_strfreev(string_list);
-
-	llinfos <<"store_filesnames: marker D" << llendl;
-	
-	llinfos << sfs->fileVector.size() << " filename(s) selected:" << llendl;
-	U32 x;
-	for (x=0; x<sfs->fileVector.size(); ++x)
-		llinfos << x << ":" << sfs->fileVector[x] << llendl;
+	gtk_widget_destroy(widget);
+	gtk_main_quit();
 }
 
-GtkWindow* LLFilePicker::buildFilePicker(void)
+
+GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder,
+					 std::string context)
 {
 	if (ll_try_gtk_init() &&
 	    ! gViewerWindow->getWindow()->getFullscreen())
 	{
 		GtkWidget *win = NULL;
-
-		win = gtk_file_selection_new(NULL);
+		GtkFileChooserAction pickertype =
+			is_save?
+			(is_folder?
+			 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER :
+			 GTK_FILE_CHOOSER_ACTION_SAVE) :
+			(is_folder?
+			 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
+			 GTK_FILE_CHOOSER_ACTION_OPEN);
+
+		win = gtk_file_chooser_dialog_new(NULL, NULL,
+						  pickertype,
+						  GTK_STOCK_CANCEL,
+						   GTK_RESPONSE_CANCEL,
+						  is_folder ?
+						  GTK_STOCK_APPLY :
+						  (is_save ? 
+						   GTK_STOCK_SAVE :
+						   GTK_STOCK_OPEN),
+						   GTK_RESPONSE_ACCEPT,
+						  NULL);
 		mStoreFilenames.win = win;
+		mStoreFilenames.contextName = context;
+
+		// get the default path for this usage context if it's been
+		// seen before.
+		std::map<std::string,std::string>::iterator
+			this_path = sContextToPathMap.find(context);
+		if (this_path != sContextToPathMap.end())
+		{
+			gtk_file_chooser_set_current_folder
+				(GTK_FILE_CHOOSER(win),
+				 this_path->second.c_str());
+		}
 
 #  if LL_X11
 		// Make GTK tell the window manager to associate this
@@ -1010,33 +1044,17 @@ GtkWindow* LLFilePicker::buildFilePicker(void)
 		}
 #  endif //LL_X11
 
-		g_signal_connect (G_OBJECT(win), "destroy",
-				  G_CALLBACK(gtk_main_quit), NULL);
-
-		// on 'ok', grab the file selection list
-		g_signal_connect (GTK_FILE_SELECTION(win)->ok_button,
-				  "clicked",
-				  G_CALLBACK(store_filenames),
+		g_signal_connect (GTK_FILE_CHOOSER(win),
+				  "response",
+				  G_CALLBACK(chooser_responder),
 				  &mStoreFilenames);
 
-		// both 'ok' and 'cancel' will end the dialog
-		g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(win)->
-						   ok_button),
-					  "clicked",
-					  G_CALLBACK(gtk_widget_destroy),
-					  G_OBJECT(win));
-		g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(win)->
-						   cancel_button),
-					  "clicked",
-					  G_CALLBACK(gtk_widget_destroy),
-					  G_OBJECT(win));
-
-		gtk_file_selection_show_fileop_buttons(GTK_FILE_SELECTION(win));
-		gtk_file_selection_set_select_multiple(GTK_FILE_SELECTION(win),
-						       FALSE);
-
 		gtk_window_set_modal(GTK_WINDOW(win), TRUE);
 
+		/* GTK 2.6: if (is_folder)
+			gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win),
+			TRUE); */
+
 		return GTK_WINDOW(win);
 	}
 	else
@@ -1045,6 +1063,65 @@ GtkWindow* LLFilePicker::buildFilePicker(void)
 	}
 }
 
+static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter,
+					     GtkWindow *picker,
+					     std::string filtername)
+{	
+	gtk_file_filter_set_name(gfilter, filtername.c_str());
+	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
+				    gfilter);
+	GtkFileFilter *allfilter = gtk_file_filter_new();
+	gtk_file_filter_add_pattern(allfilter, "*");
+	gtk_file_filter_set_name(allfilter, "All Files");
+	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter);
+	gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter);
+}
+
+static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker,
+							   std::string pattern,
+							   std::string filtername)
+{
+	GtkFileFilter *gfilter = gtk_file_filter_new();
+	gtk_file_filter_add_pattern(gfilter, pattern.c_str());
+	add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+	return filtername;
+}
+
+static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker,
+							std::string mime,
+							std::string filtername)
+{
+	GtkFileFilter *gfilter = gtk_file_filter_new();
+	gtk_file_filter_add_mime_type(gfilter, mime.c_str());
+	add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+	return filtername;
+}
+
+static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker)
+{
+	return add_simple_mime_filter_to_gtkchooser(picker,  "audio/x-wav",
+						    "Sounds (*.wav)");
+}
+
+static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker)
+{
+	return add_simple_pattern_filter_to_gtkchooser(picker,  "*.bvh",
+						       "Animations (*.bvh)");
+}
+
+static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
+{
+	GtkFileFilter *gfilter = gtk_file_filter_new();
+	gtk_file_filter_add_pattern(gfilter, "*.tga");
+	gtk_file_filter_add_mime_type(gfilter, "image/jpeg");
+	gtk_file_filter_add_mime_type(gfilter, "image/png");
+	gtk_file_filter_add_mime_type(gfilter, "image/bmp");
+	std::string filtername = "Images (*.tga; *.bmp; *.jpg; *.png)";
+	add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+	return filtername;
+}
+
+
 BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
 {
 	BOOL rtn = FALSE;
@@ -1052,7 +1129,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
 	gViewerWindow->mWindow->beforeDialog();
 
 	reset();
-	GtkWindow* picker = buildFilePicker();
+	GtkWindow* picker = buildFilePicker(true, false, "savefile");
 
 	if (picker)
 	{
@@ -1062,36 +1139,45 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
 		switch (filter)
 		{
 		case FFSAVE_WAV:
-			caption += "Sounds (*.wav)";
-			suggest_ext += ".wav";
+			caption += add_wav_filter_to_gtkchooser(picker);
+			suggest_ext = ".wav";
 			break;
 		case FFSAVE_TGA:
-			caption += "Targa Images (*.tga)";
-			suggest_ext += ".tga";
+			caption += add_simple_pattern_filter_to_gtkchooser
+				(picker, "*.tga", "Targa Images (*.tga)");
+			suggest_ext = ".tga";
 			break;
 		case FFSAVE_BMP:
-			caption += "Bitmap Images (*.bmp)";
-			suggest_ext += ".bmp";
+			caption += add_simple_mime_filter_to_gtkchooser
+				(picker, "image/bmp", "Bitmap Images (*.bmp)");
+			suggest_ext = ".bmp";
 			break;
 		case FFSAVE_AVI:
-			caption += "AVI Movie File (*.avi)";
-			suggest_ext += ".avi";
+			caption += add_simple_mime_filter_to_gtkchooser
+				(picker, "video/x-msvideo",
+				 "AVI Movie File (*.avi)");
+			suggest_ext = ".avi";
 			break;
 		case FFSAVE_ANIM:
-			caption += "XAF Anim File (*.xaf)";
-			suggest_ext += ".xaf";
+			caption += add_simple_pattern_filter_to_gtkchooser
+				(picker, "*.xaf", "XAF Anim File (*.xaf)");
+			suggest_ext = ".xaf";
 			break;
 		case FFSAVE_XML:
-			caption += "XML File (*.xml)";
-			suggest_ext += ".xml";
+			caption += add_simple_pattern_filter_to_gtkchooser
+				(picker, "*.xml", "XML File (*.xml)");
+			suggest_ext = ".xml";
 			break;
 		case FFSAVE_RAW:
-			caption += "RAW File (*.raw)";
-			suggest_ext += ".raw";
+			caption += add_simple_pattern_filter_to_gtkchooser
+				(picker, "*.raw", "RAW File (*.raw)");
+			suggest_ext = ".raw";
 			break;
 		case FFSAVE_J2C:
-			caption += "Compressed Images (*.j2c)";
-			suggest_ext += ".j2c";
+			caption += add_simple_mime_filter_to_gtkchooser
+				(picker, "images/jp2",
+				 "Compressed Images (*.j2c)");
+			suggest_ext = ".j2c";
 			break;
 		default:;
 			break;
@@ -1103,27 +1189,19 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const char* filename )
 		{
 			suggest_name += suggest_ext;
 
-			gtk_file_selection_set_filename
-				(GTK_FILE_SELECTION(picker),
-				 g_filename_from_utf8(suggest_name.c_str(),
-						      -1, NULL,
-						      NULL,
-						      NULL));
-			gtk_editable_select_region(GTK_EDITABLE(GTK_FILE_SELECTION(picker)->selection_entry), 0, suggest_name.length() - suggest_ext.length() );
+			gtk_file_chooser_set_current_name
+				(GTK_FILE_CHOOSER(picker),
+				 suggest_name.c_str());
 		}
 		else
 		{
-			gtk_file_selection_set_filename
-				(GTK_FILE_SELECTION(picker),
-				 g_filename_from_utf8(filename,
-						      -1, NULL,
-						      NULL,
-						      NULL));
-			gtk_editable_select_region(GTK_EDITABLE(GTK_FILE_SELECTION(picker)->selection_entry), 0, -1 );
+			gtk_file_chooser_set_current_name
+				(GTK_FILE_CHOOSER(picker), filename);
 		}
 
 		gtk_widget_show_all(GTK_WIDGET(picker));
 		gtk_main();
+
 		rtn = (mStoreFilenames.fileVector.size() == 1);
 	}
 
@@ -1139,27 +1217,34 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
 	gViewerWindow->mWindow->beforeDialog();
 
 	reset();
-	GtkWindow* picker = buildFilePicker();
+	GtkWindow* picker = buildFilePicker(false, false, "openfile");
 
 	if (picker)
 	{
 		std::string caption = "Load ";
+		std::string filtername = "";
 		switch (filter)
 		{
 		case FFLOAD_WAV:
-			caption += "Sounds (*.wav)"; break;
+			filtername = add_wav_filter_to_gtkchooser(picker);
+			break;
 		case FFLOAD_ANIM:
-			caption += "Animations (*.bvh)"; break;
+			filtername = add_bvh_filter_to_gtkchooser(picker);
+			break;
 		case FFLOAD_IMAGE:
-			caption += "Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)"; break;
+			filtername = add_imageload_filter_to_gtkchooser(picker);
+			break;
 		default:;
 			break;
 		}
+
+		caption += filtername;
 		
 		gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
 
 		gtk_widget_show_all(GTK_WIDGET(picker));
 		gtk_main();
+
 		rtn = (mStoreFilenames.fileVector.size() == 1);
 	}
 
@@ -1175,12 +1260,12 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
 	gViewerWindow->mWindow->beforeDialog();
 
 	reset();
-	GtkWindow* picker = buildFilePicker();
+	GtkWindow* picker = buildFilePicker(false, false, "openfile");
 
 	if (picker)
 	{
-		gtk_file_selection_set_select_multiple(GTK_FILE_SELECTION(picker),
-						       TRUE);
+		gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker),
+						      TRUE);
 
 		gtk_window_set_title(GTK_WINDOW(picker), "Load Files");
 
@@ -1221,7 +1306,8 @@ const char* LLFilePicker::getDirname()
 		const char* fullpath = mStoreFilenames.fileVector[index].c_str();
 		const char* finalpart = NULL;
 		const char* thispart = fullpath;
-		// walk through the string looking for the final dirsep, i.e. /
+		// (Hmm, is the strstr of dirsep UTF-8-correct?  Yes, reckon.)
+		// Walk through the string looking for the final dirsep, i.e. /
 		do
 		{
 			thispart = strstr(thispart, dirsep);
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index c04279ee917d56cdbcd83705c905481832844f52..bb63e33fe55a0f2e457f833cd4e7ea8157712d19 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -50,11 +50,16 @@
 typedef struct {
 	GtkWidget *win;
 	std::vector<LLString> fileVector;
+	std::string contextName;
 } StoreFilenamesStruct;
 #endif // LL_GTK
 
 class LLFilePicker
 {
+#ifdef LL_GTK
+	friend class LLDirPicker;
+	friend void chooser_responder(GtkWidget *, gint, gpointer);
+#endif // LL_GTK
 public:
 	// calling this before main() is undefined
 	static LLFilePicker& instance( void ) { return sInstance; }
@@ -146,9 +151,9 @@ class LLFilePicker
 
 #if LL_GTK
 	StoreFilenamesStruct mStoreFilenames;
-
-	GtkWindow* buildFilePicker(void);
 	U32 mNextFileIndex;
+	// we remember the last path that was accessed for a particular usage
+	static std::map <std::string, std::string> sContextToPathMap;
 #endif
 
 	char mFiles[FILENAME_BUFFER_SIZE];	/*Flawfinder: ignore*/
@@ -159,6 +164,12 @@ class LLFilePicker
 
 	static LLFilePicker sInstance;
 	
+protected:
+#if LL_GTK
+        GtkWindow* buildFilePicker(bool is_save, bool is_folder,
+				   std::string context = "generic");
+#endif
+
 public:
 	// don't call these directly please.
 	LLFilePicker();