Bug 796994 - Replace obsolete filepicker.show with filepicker.open in suite. r=IanN a=IanN
authorFrank-Rainer Grahl <frgrahl@gmx.net>
Sat, 03 Feb 2018 13:19:37 +0100
changeset 30521 919d80f33c8fc63b98b08035cca6ef36b1dc11d3
parent 30520 756d53caf14f9125a69f7a28f38fd224ceef7052
child 30522 5ace949bc4a44fc83629d557dc51301a7d337303
push idunknown
push userunknown
push dateunknown
reviewersIanN, IanN
bugs796994
Bug 796994 - Replace obsolete filepicker.show with filepicker.open in suite. r=IanN a=IanN
suite/browser/navigator.js
suite/browser/pageinfo/pageInfo.js
suite/common/bookmarks/bookmarksManager.js
suite/common/openLocation.js
suite/common/pref/pref-applications.js
suite/common/pref/pref-cache.js
suite/common/pref/pref-download.js
suite/common/pref/pref-navigator.js
suite/common/pref/preferences.js
suite/common/sync/syncUtils.js
suite/components/feeds/FeedWriter.js
suite/mailnews/addrbook/abCardOverlay.js
suite/mailnews/compose/MsgComposeCommands.js
suite/mailnews/mailWindowOverlay.js
--- a/suite/browser/navigator.js
+++ b/suite/browser/navigator.js
@@ -1,14 +1,15 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/DownloadTaskbarProgress.jsm");
 ChromeUtils.import("resource:///modules/WindowsPreviewPerTab.jsm");
 
 this.__defineGetter__("PluralForm", function() {
   ChromeUtils.import("resource://gre/modules/PluralForm.jsm");
   return this.PluralForm;
 });
 this.__defineSetter__("PluralForm", function (val) {
@@ -16,16 +17,17 @@ this.__defineSetter__("PluralForm", func
   return this.PluralForm = val;
 });
 
 ChromeUtils.defineModuleGetter(this, "SafeBrowsing",
   "resource://gre/modules/SafeBrowsing.jsm");
 
 const REMOTESERVICE_CONTRACTID = "@mozilla.org/toolkit/remote-service;1";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
 var gURLBar = null;
 var gProxyButton = null;
 var gProxyFavIcon = null;
 var gProxyDeck = null;
 var gNavigatorBundle;
 var gBrandBundle;
 var gNavigatorRegionBundle;
 var gLastValidURLStr = "";
@@ -1507,59 +1509,124 @@ function BrowserOpenTab()
       setTimeout(WindowFocusTimerCallback, 0, content);
   }
 }
 
 function BrowserOpenSyncTabs()
 {
   switchToTabHavingURI("about:sync-tabs", true);
 }
-
-/* Show file picker dialog configured for opening a file, and return
- * the selected nsIFileURL instance. */
-function selectFileToOpen(label, prefRoot)
-{
-  var fileURL = null;
+// Class for saving the last directory and filter Index in the prefs.
+// Used for open file and upload file.
+class RememberLastDir {
+
+  // The pref names are constructed from the prefix parameter in the constructor.
+  // The pref names should not be changed later.
+  constructor(prefPrefix) {
+    this._prefLastDir = prefPrefix + ".lastDir";
+    this._prefFilterIndex = prefPrefix + ".filterIndex";
+    this._lastDir = null;
+    this._lastFilterIndex =  null;
+  }
+
+  get path() {
+    if (!this._lastDir || !this._lastDir.exists()) {
+      try {
+        this._lastDir = Services.prefs.getComplexValue(this._prefLastDir,
+                                                       Ci.nsIFile);
+        if (!this._lastDir.exists()) {
+          this._lastDir = null;
+        }
+      } catch (e) {}
+    }
+    return this._lastDir;
+  }
+
+  set path(val) {
+    try {
+      if (!val || !val.isDirectory()) {
+        return;
+      }
+    } catch (e) {
+      return;
+    }
+    this._lastDir = val.clone();
+
+    // Don't save the last open directory pref inside the Private Browsing mode
+    if (!gPrivate) {
+      Services.prefs.setComplexValue(this._prefLastDir,
+                                     Ci.nsIFile,
+                                     this._lastDir);
+    }
+  }
+
+  get filterIndex() {
+    if (!this._lastFilterIndex) {
+      // use a pref to remember the filterIndex selected by the user.
+      this._lastFilterIndex =
+        Services.prefs.getIntPref(this._prefFilterIndex, 0);
+    }
+    return this._lastFilterIndex;
+  }
+
+  set filterIndex(val) {
+    // If the default is picked the filter is null.
+    this._lastFilterIndex = val ? val : 0;
+
+    // Don't save the last filter index inside the Private Browsing mode
+    if (!gPrivate) {
+      Services.prefs.setIntPref(this._prefFilterIndex,
+                                this._lastFilterIndex);
+    }
+  }
+
+  // This is currently not used.
+  reset() {
+    this._lastDir = null;
+    this._lastFilterIndex = null;
+  }
+}
+
+var gLastOpenDirectory;
+
+function BrowserOpenFileWindow() {
+
+  if (!gLastOpenDirectory) {
+   gLastOpenDirectory = new RememberLastDir("browser.open");
+  };
 
   // Get filepicker component.
-  const nsIFilePicker = Ci.nsIFilePicker;
-  var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
-  fp.init(window, gNavigatorBundle.getString(label), nsIFilePicker.modeOpen);
-  fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
-                   nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
-
-  const filterIndexPref = prefRoot + "filterIndex";
-  const lastDirPref = prefRoot + "dir";
-
-  // use a pref to remember the filterIndex selected by the user.
-  fp.filterIndex = GetIntPref(filterIndexPref, 0);
-
-  // use a pref to remember the displayDirectory selected by the user.
   try {
-    fp.displayDirectory = Services.prefs.getComplexValue(lastDirPref,
-                              Ci.nsIFile);
+    const nsIFilePicker = Ci.nsIFilePicker;
+    let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+    let fpCallback = function fpCallback_done(aResult) {
+      if (aResult == nsIFilePicker.returnOK) {
+        try {
+          // Set last path and file index only if file is ok.
+          if (fp.file) {
+            gLastOpenDirectory.filterIndex = fp.filterIndex;
+            gLastOpenDirectory.path =
+              fp.file.parent.QueryInterface(Ci.nsIFile);
+          }
+        } catch (ex) {
+        }
+        openUILinkIn(fp.fileURL.spec, "current");
+      }
+    };
+
+    fp.init(window, gNavigatorBundle.getString("openFile"),
+            nsIFilePicker.modeOpen);
+    fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText |
+                     nsIFilePicker.filterImages | nsIFilePicker.filterXML |
+                     nsIFilePicker.filterHTML);
+    fp.filterIndex = gLastOpenDirectory.filterIndex;
+    fp.displayDirectory = gLastOpenDirectory.path;
+    fp.open(fpCallback);
   } catch (ex) {
   }
-
-  if (fp.show() == nsIFilePicker.returnOK) {
-    Services.prefs.setIntPref(filterIndexPref, fp.filterIndex);
-    Services.prefs.setComplexValue(lastDirPref,
-                                   Ci.nsIFile,
-                                   fp.file.parent);
-    fileURL = fp.fileURL;
-  }
-
-  return fileURL;
-}
-
-function BrowserOpenFileWindow()
-{
-  try {
-    openTopWin(selectFileToOpen("openFile", "browser.open.").spec);
-  } catch (e) {}
 }
 
 function updateCloseItems()
 {
   var browser = getBrowser();
 
   var hideCloseWindow = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab") &&
                         (!browser || browser.tabContainer.childNodes.length <= 1);
@@ -2645,41 +2712,59 @@ function getCurrentURI()
   var focusedWindow = document.commandDispatcher.focusedWindow;
   var contentFrame = isContentFrame(focusedWindow) ? focusedWindow : window.content;
 
   var nav = contentFrame.QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIWebNavigation);
   return nav.currentURI;
 }
 
-function uploadFile(fileURL)
-{
-  var targetBaseURI = getCurrentURI();
-
-  // generate the target URI.  we use fileURL.file.leafName to get the
-  // unicode value of the target filename w/o any URI-escaped chars.
-  // this gives the protocol handler the best chance of generating a
-  // properly formatted URI spec.  we pass null for the origin charset
-  // parameter since we want the URI to inherit the origin charset
-  // property from targetBaseURI.
-
-  var leafName = fileURL.QueryInterface(Ci.nsIFileURL).file.leafName;
-
-  var targetURI = Services.io.newURI(leafName, null, targetBaseURI);
-
-  // ok, start uploading...
-  openDialog("chrome://communicator/content/downloads/uploadProgress.xul", "",
-             "titlebar,centerscreen,minimizable,dialog=no", fileURL, targetURI);
-}
+var gLastOpenUploadDirectory;
 
 function BrowserUploadFile()
 {
-  try {
-    uploadFile(selectFileToOpen("uploadFile", "browser.upload."));
-  } catch (e) {}
+  if (!gLastOpenUploadDirectory) {
+    gLastOpenUploadDirectory = new RememberLastDir("browser.upload");
+  };
+
+  const nsIFilePicker = Ci.nsIFilePicker;
+  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+  fp.init(window, gNavigatorBundle.getString("uploadFile"), nsIFilePicker.modeOpen);
+  fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
+                   nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
+
+  // use a pref to remember the filterIndex selected by the user.
+  fp.filterIndex = gLastOpenUploadDirectory.filterIndex;
+
+  // Use a pref to remember the displayDirectory selected by the user.
+  fp.displayDirectory = gLastOpenUploadDirectory.path;
+
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK || !fp.fileURL) {
+      return;
+    }
+    gLastOpenUploadDirectory.filterIndex = fp.filterIndex;
+    gLastOpenUploadDirectory.path = fp.file.parent.QueryInterface(Ci.nsIFile);
+
+    try {
+      var targetBaseURI = getCurrentURI();
+      // Generate the target URI. We use fileURL.file.leafName to get the
+      // unicode value of the target filename w/o any URI-escaped chars.
+      // this gives the protocol handler the best chance of generating a
+      // properly formatted URI spec.  we pass null for the origin charset
+      // parameter since we want the URI to inherit the origin charset
+      // property from targetBaseURI.
+      var leafName = fp.fileURL.QueryInterface(Ci.nsIFileURL).file.leafName;
+      var targetURI = Services.io.newURI(leafName, null, targetBaseURI);
+
+       // ok, start uploading...
+      openDialog("chrome://communicator/content/downloads/uploadProgress.xul", "",
+               "titlebar,centerscreen,minimizable,dialog=no", fp.fileURL, targetURI);
+    } catch (e) {}
+  });
 }
 
 /* This function is called whenever the file menu is about to be displayed.
  * Enable the upload menu item if appropriate. */
 function updateFileUploadItem()
 {
   var canUpload = false;
   try {
--- a/suite/browser/pageinfo/pageInfo.js
+++ b/suite/browser/pageinfo/pageInfo.js
@@ -844,39 +844,42 @@ function getSelectedImage(tree)
     return null;
 
   // Only works if only one item is selected
   var clickedRow = tree.currentIndex;
   // image-node
   return gImageView.data[clickedRow][COL_IMAGE_NODE];
 }
 
-function selectSaveFolder()
-{
+function selectSaveFolder(aCallback) {
   const nsIFile = Ci.nsIFile;
   const nsIFilePicker = Ci.nsIFilePicker;
-  var fp = Cc["@mozilla.org/filepicker;1"]
+  let titleText = gBundle.getString("mediaSelectFolder");
+  let fp = Cc["@mozilla.org/filepicker;1"]
              .createInstance(nsIFilePicker);
+  let fpCallback = function fpCallback_done(aResult) {
+    if (aResult == nsIFilePicker.returnOK) {
+      aCallback(fp.file.QueryInterface(nsIFile));
+    } else {
+      aCallback(null);
+    }
+  };
 
-  var titleText = gBundle.getString("mediaSelectFolder");
   fp.init(window, titleText, nsIFilePicker.modeGetFolder);
-  var initialDir = GetLocalFilePref("browser.download.lastDir");
-  if (!initialDir) {
-    let dnldMgr = Cc["@mozilla.org/download-manager;1"]
-                    .getService(Ci.nsIDownloadManager);
-    initialDir = dnldMgr.userDownloadsDirectory;
+  fp.appendFilters(nsIFilePicker.filterAll);
+  try {
+    let prefs = Cc[PREFERENCES_CONTRACTID]
+                  .getService(Ci.nsIPrefBranch);
+    let initialDir = prefs.getComplexValue("browser.download.dir", nsIFile);
+    if (initialDir) {
+      fp.displayDirectory = initialDir;
+    }
+  } catch (ex) {
   }
-  fp.displayDirectory = initialDir;
-
-  fp.appendFilters(nsIFilePicker.filterAll);
-  var ret = fp.show();
-
-  if (ret == nsIFilePicker.returnOK)
-    return fp.file.QueryInterface(nsIFile);
-  return null;
+  fp.open(fpCallback);
 }
 
 function saveMedia()
 {
   var tree = document.getElementById("imagetree");
   var count = tree.view.selection.count;
   if (count == 1) {
     var item = getSelectedImage(tree);
@@ -888,57 +891,53 @@ function saveMedia()
       if (item instanceof HTMLVideoElement)
         titleKey = "SaveVideoTitle";
       else if (item instanceof HTMLAudioElement)
         titleKey = "SaveAudioTitle";
 
       saveURL(url, null, titleKey, false, true, makeURI(item.baseURI),
               gDocument);
     }
-  }
-  else {
-    var odir  = selectSaveFolder();
-    var start = { };
-    var end   = { };
-    var numRanges = tree.view.selection.getRangeCount();
+  } else {
+    selectSaveFolder(function(aDirectory) {
+      if (aDirectory) {
+        var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
+          uniqueFile(aChosenData.file);
+          internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
+                       aChosenData, aBaseURI, null, false, null, gDocument.isContentWindowPrivate);
+        };
 
-    var rowArray = [ ];
-    for (var t = 0; t < numRanges; t++) {
-      tree.view.selection.getRangeAt(t, start, end);
-      for (var v = start.value; v <= end.value; v++)
-        rowArray.push(v);
-    }
-
-    var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
-      internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
-                   aChosenData, aBaseURI, gDocument);
-    }
+        for (var i = 0; i < rowArray.length; i++) {
+          let v = rowArray[i];
+          let dir = aDirectory.clone();
+          let item = gImageView.data[v][COL_IMAGE_NODE];
+          let uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
+          let uri = makeURI(uriString);
 
-    for (var i = 0; i < rowArray.length; i++) {
-      var v = rowArray[i];
-      var dir = odir.clone();
-      var item = gImageView.data[v][COL_IMAGE_NODE];
-      var uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
-      var uri = makeURI(uriString);
+          try {
+            uri.QueryInterface(Ci.nsIURL);
+            dir.append(decodeURIComponent(uri.fileName));
+          } catch (ex) {
+            // data:/blob: uris
+            // Supply a dummy filename, otherwise Download Manager
+            // will try to delete the base directory on failure.
+            dir.append(gImageView.data[v][COL_IMAGE_TYPE]);
+          }
 
-      try {
-        uri.QueryInterface(Ci.nsIURL);
-        dir.append(decodeURIComponent(uri.fileName));
+          if (i == 0) {
+            saveAnImage(uriString, new AutoChosen(dir, uri), makeURI(item.baseURI));
+          } else {
+            // This delay is a hack which prevents the download manager
+            // from opening many times. See bug 377339.
+            setTimeout(saveAnImage, 200, uriString, new AutoChosen(dir, uri),
+                       makeURI(item.baseURI));
+          }
+        }
       }
-      catch(ex) { /* data: uris */ }
-
-      if (i == 0)
-        saveAnImage(uriString, new AutoChosen(dir, uri), makeURI(item.baseURI));
-      else {
-        // This delay is a hack which prevents the download manager
-        // from opening many times. See bug 377339.
-        setTimeout(saveAnImage, 200, uriString, new AutoChosen(dir, uri),
-                   makeURI(item.baseURI));
-      }
-    }
+    });
   }
 }
 
 function onBlockImage(aChecked)
 {
   var uri = makeURI(document.getElementById("imageurltext").value);
   if (aChecked)
     Services.perms.add(uri, "image", Services.perms.DENY_ACTION);
--- a/suite/common/bookmarks/bookmarksManager.js
+++ b/suite/common/bookmarks/bookmarksManager.js
@@ -319,45 +319,51 @@ var PlacesOrganizer = {
     if (window.fromFile)
       this.importFromFile();
   },
 
   /**
    * Open a file-picker and import the selected file into the bookmarks store
    */
   importFromFile: function PO_importFromFile() {
-    var fp = Cc["@mozilla.org/filepicker;1"]
+    let fp = Cc["@mozilla.org/filepicker;1"]
                .createInstance(Ci.nsIFilePicker);
+    let fpCallback = function fpCallback_done(aResult) {
+      if (aResult != Ci.nsIFilePicker.returnCancel && fp.fileURL) {
+        ChromeUtils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
+        BookmarkHTMLUtils.importFromURL(fp.fileURL.spec, false)
+                         .catch(Cu.reportError);
+      }
+    };
+
     fp.init(window, PlacesUIUtils.getString("SelectImport"),
             Ci.nsIFilePicker.modeOpen);
     fp.appendFilters(Ci.nsIFilePicker.filterHTML);
-    if (fp.show() != Ci.nsIFilePicker.returnCancel) {
-      if (fp.fileURL) {
-        ChromeUtils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
-        BookmarkHTMLUtils.importFromURL(fp.fileURL.spec, false)
-                         .then(null, Cu.reportError);
-      }
-    }
+    fp.open(fpCallback);
   },
 
   /**
    * Allows simple exporting of bookmarks.
    */
   exportBookmarks: function PO_exportBookmarks() {
-    var fp = Cc["@mozilla.org/filepicker;1"]
+    let fp = Cc["@mozilla.org/filepicker;1"]
                .createInstance(Ci.nsIFilePicker);
+    let fpCallback = function fpCallback_done(aResult) {
+      if (aResult != Ci.nsIFilePicker.returnCancel) {
+        ChromeUtils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
+        BookmarkHTMLUtils.exportToFile(fp.file.path)
+                         .catch(Cu.reportError);
+      }
+    };
+
     fp.init(window, PlacesUIUtils.getString("EnterExport"),
             Ci.nsIFilePicker.modeSave);
     fp.appendFilters(Ci.nsIFilePicker.filterHTML);
     fp.defaultString = "bookmarks.html";
-    if (fp.show() != Ci.nsIFilePicker.returnCancel) {
-      ChromeUtils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
-      BookmarkHTMLUtils.exportToFile(fp.file)
-                       .then(null, Cu.reportError);
-    }
+    fp.open(fpCallback);
   },
 
   /**
    * Populates the restore menu with the dates of the backups available.
    */
   populateRestoreMenu: function PO_populateRestoreMenu() {
     let restorePopup = document.getElementById("fileRestorePopup");
 
@@ -405,28 +411,31 @@ var PlacesOrganizer = {
     }
   },
 
   /**
    * Called when 'Choose File...' is selected from the restore menu.
    * Prompts for a file and restores bookmarks to those in the file.
    */
   onRestoreBookmarksFromFile: function PO_onRestoreBookmarksFromFile() {
-    var fp = Cc["@mozilla.org/filepicker;1"]
+    let fp = Cc["@mozilla.org/filepicker;1"]
                .createInstance(Ci.nsIFilePicker);
+    let fpCallback = aResult => {
+      if (aResult != Ci.nsIFilePicker.returnCancel) {
+        this.restoreBookmarksFromFile(fp.file);
+      }
+    };
+
     fp.init(window, PlacesUIUtils.getString("bookmarksRestoreTitle"),
             Ci.nsIFilePicker.modeOpen);
     fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
                     PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
     fp.appendFilters(Ci.nsIFilePicker.filterAll);
-
     fp.displayDirectory = GetDesktopFolder();
-
-    if (fp.show() != Ci.nsIFilePicker.returnCancel)
-      this.restoreBookmarksFromFile(fp.file);
+    fp.open(fpCallback);
   },
 
   /**
    * Restores bookmarks from a JSON file.
    */
   restoreBookmarksFromFile: function PO_restoreBookmarksFromFile(aFile) {
     // check file extension
     if (!/\.json(?:lz4)?$/i.test(aFile.leafName)) {
@@ -453,32 +462,37 @@ var PlacesOrganizer = {
   },
 
   /**
    * Backup bookmarks to desktop, auto-generate a filename with a date.
    * The file is a JSON serialization of bookmarks, tags and any annotations
    * of those items.
    */
   backupBookmarks: function PO_backupBookmarks() {
-    var fp = Cc["@mozilla.org/filepicker;1"]
+    let fp = Cc["@mozilla.org/filepicker;1"]
                .createInstance(Ci.nsIFilePicker);
+    let fpCallback = function fpCallback_done(aResult) {
+      if (aResult != Ci.nsIFilePicker.returnCancel) {
+        // There is no OS.File version of the filepicker yet (Bug 937812).
+        PlacesBackups.saveBookmarksToJSONFile(fp.file.path);
+      }
+    };
+
     fp.init(window, PlacesUIUtils.getString("bookmarksBackupTitle"),
             Ci.nsIFilePicker.modeSave);
     fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
                     PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
 
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"]
                    .getService(Ci.nsIProperties);
     var backupsDir = dirSvc.get("Desk", Ci.nsIFile);
     fp.displayDirectory = backupsDir;
-
     fp.defaultString = PlacesBackups.getFilenameForDate();
-
-    if (fp.show() != Ci.nsIFilePicker.returnCancel)
-      PlacesBackups.saveBookmarksToJSONFile(fp.file);
+    fp.defaultExtension = "json";
+    fp.open(fpCallback);
   },
 
   _paneDisabled: false,
   _setDetailsFieldsDisabledState:
   function PO__setDetailsFieldsDisabledState(aDisabled) {
     if (aDisabled) {
       document.getElementById("paneElementsBroadcaster")
               .setAttribute("disabled", "true");
--- a/suite/common/openLocation.js
+++ b/suite/common/openLocation.js
@@ -87,36 +87,39 @@ function accept()
   }
 
   SetStringPref(gLastPref, gInput.value);
 }
 
 function onChooseFile()
 {
   const nsIFilePicker = Ci.nsIFilePicker;
-  try {
-    var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
-    fp.init(window, gBundle.getString("chooseFileDialogTitle"), nsIFilePicker.modeOpen);
-    if (window.arguments[0].action != "5" && gOpenAppList.value == "2") {
-      // When loading into Composer, direct user to prefer HTML files and text
-      // files, so we call separately to control the order of the filter list.
-      fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterText);
-      fp.appendFilters(nsIFilePicker.filterAll);
-    }
-    else {
-      fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterText |
-                       nsIFilePicker.filterAll | nsIFilePicker.filterImages | nsIFilePicker.filterXML);
+  let fp = Cc["@mozilla.org/filepicker;1"]
+             .createInstance(nsIFilePicker);
+  fp.init(window, gBundle.getString("chooseFileDialogTitle"),
+          nsIFilePicker.modeOpen);
+  if (window.arguments[0].action != "5" && gOpenAppList.value == "2") {
+    // When loading into Composer, direct user to prefer HTML files and text
+    // files, so we call separately to control the order of the filter list.
+    fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterText);
+    fp.appendFilters(nsIFilePicker.filterAll);
+  } else {
+    fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterText |
+                     nsIFilePicker.filterAll | nsIFilePicker.filterImages |
+                     nsIFilePicker.filterXML);
+  }
+  
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK && fp.fileURL.spec && 
+        fp.fileURL.spec.length > 0) {
+      gInput.value = fp.fileURL.spec;
     }
 
-    if (fp.show() == nsIFilePicker.returnOK && fp.fileURL.spec && fp.fileURL.spec.length > 0)
-      gInput.value = fp.fileURL.spec;
-  }
-  catch(ex) {
-  }
-  doEnabling();
+    doEnabling();
+  });
 }
 
 function useUBHistoryItem(aValue)
 {
   gInput.value = aValue;
   gInput.focus();
   doEnabling();
 }
--- a/suite/common/pref/pref-applications.js
+++ b/suite/common/pref/pref-applications.js
@@ -1,14 +1,16 @@
 /* -*- Mode: Java; tab-width: 2; c-basic-offset: 2; -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+
 function Startup()
 {
   gApplicationsPane.init();
 }
 
 //****************************************************************************//
 // Constants & Enumeration Values
 
@@ -1566,87 +1568,93 @@ var gApplicationsPane = {
         typeItem.setAttribute("actionIcon", sysIcon);
       else
         typeItem.setAttribute("appHandlerIcon", "app");
     }
   },
 
   chooseApp: function() {
     var handlerApp;
-
-#ifdef XP_WIN
-    var params = {};
-    var handlerInfo = this._handledTypes[this._list.selectedItem.type];
-
-    if (isFeedType(handlerInfo.type)) {
-      // MIME info will be null, create a temp object.
-      params.mimeInfo = mimeSvc.getFromTypeAndExtension(handlerInfo.type,
-                                                 handlerInfo.primaryExtension);
-    } else {
-      params.mimeInfo = handlerInfo.wrappedHandlerInfo;
-    }
-
-    params.title         = this._prefsBundle.getString("fpTitleChooseApp");
-    params.description   = handlerInfo.description;
-    params.filename      = null;
-    params.handlerApp    = null;
-
-    window.openDialog("chrome://global/content/appPicker.xul", null,
-                      "chrome,modal,centerscreen,titlebar,dialog=yes",
-                      params);
-
-    if (this.isValidHandlerApp(params.handlerApp)) {
-      handlerApp = params.handlerApp;
-
-      // Add the app to the type's list of possible handlers.
-      handlerInfo.addPossibleApplicationHandler(handlerApp);
-    }
-#else
-    var fp = Cc["@mozilla.org/filepicker;1"]
-               .createInstance(nsIFilePicker);
-    var winTitle = this._prefsBundle.getString("fpTitleChooseApp");
-    fp.init(window, winTitle, nsIFilePicker.modeOpen);
-    fp.appendFilters(nsIFilePicker.filterApps);
+    let onSelectionDone = function() {
+      // Rebuild the actions menu whether the user picked an app or canceled.
+      // If they picked an app, we want to add the app to the menu and select it.
+      // If they canceled, we want to go back to their previous selection.
+      this.rebuildActionsMenu();
 
-    // Prompt the user to pick an app.  If they pick one, and it's a valid
-    // selection, then add it to the list of possible handlers.
-    if (fp.show() == nsIFilePicker.returnOK && fp.file &&
-        this._isValidHandlerExecutable(fp.file)) {
-      handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
-                     .createInstance(nsILocalHandlerApp);
-      handlerApp.name = getFileDisplayName(fp.file);
-      handlerApp.executable = fp.file;
-
-      // Add the app to the type's list of possible handlers.
-      let handlerInfo = this._handledTypes[this._list.selectedItem.type];
-      handlerInfo.addPossibleApplicationHandler(handlerApp);
-    }
-#endif
-
-    // Rebuild the actions menu whether the user picked an app or canceled.
-    // If they picked an app, we want to add the app to the menu and select it.
-    // If they canceled, we want to go back to their previous selection.
-    this.rebuildActionsMenu();
-
-    // If the user picked a new app from the menu, select it.
-    if (handlerApp) {
-      let typeItem = this._list.selectedItem;
-      var actionsCell =
-        document.getAnonymousElementByAttribute(typeItem, "anonid", "action-cell");
-      var actionsMenu =
-        document.getAnonymousElementByAttribute(actionsCell, "anonid", "action-menu");
-      let menuItems = actionsMenu.menupopup.childNodes;
-      for (let i = 0; i < menuItems.length; i++) {
-        let menuItem = menuItems[i];
-        if (menuItem.handlerApp && menuItem.handlerApp.equals(handlerApp)) {
-          actionsMenu.selectedIndex = i;
-          this.onSelectAction(menuItem);
-          break;
+      // If the user picked a new app from the menu, select it.
+      if (handlerApp) {
+        let typeItem = this._list.selectedItem;
+        var actionsCell =
+          document.getAnonymousElementByAttribute(typeItem, "anonid", "action-cell");
+        var actionsMenu =
+          document.getAnonymousElementByAttribute(actionsCell, "anonid", "action-menu");
+        let menuItems = actionsMenu.menupopup.childNodes;
+        for (let i = 0; i < menuItems.length; i++) {
+          let menuItem = menuItems[i];
+          if (menuItem.handlerApp && menuItem.handlerApp.equals(handlerApp)) {
+            actionsMenu.selectedIndex = i;
+            this.onSelectAction(menuItem);
+            break;
+          }
         }
       }
+    }.bind(this);
+
+    if (AppConstants.platform == "win") {
+      let params = {};
+      let handlerInfo = this._handledTypes[this._list.selectedItem.type];
+
+      if (isFeedType(handlerInfo.type)) {
+        // MIME info will be null, create a temp object.
+        params.mimeInfo = mimeSvc.getFromTypeAndExtension(handlerInfo.type,
+                                                   handlerInfo.primaryExtension);
+      } else {
+        params.mimeInfo = handlerInfo.wrappedHandlerInfo;
+      }
+
+      params.title         = this._prefsBundle.getString("fpTitleChooseApp");
+      params.description   = handlerInfo.description;
+      params.filename      = null;
+      params.handlerApp    = null;
+
+      window.openDialog("chrome://global/content/appPicker.xul", null,
+                        "chrome,modal,centerscreen,titlebar,dialog=yes",
+                        params);
+
+      if (this.isValidHandlerApp(params.handlerApp)) {
+        handlerApp = params.handlerApp;
+
+        // Add the app to the type's list of possible handlers.
+        handlerInfo.addPossibleApplicationHandler(handlerApp);
+      }
+      onSelectionDone();
+    } else {
+      const nsIFilePicker = Ci.nsIFilePicker;
+      let fp = Cc["@mozilla.org/filepicker;1"]
+                 .createInstance(nsIFilePicker);
+      let winTitle = this._prefsBundle.getString("fpTitleChooseApp");
+      fp.init(window, winTitle, nsIFilePicker.modeOpen);
+      fp.appendFilters(nsIFilePicker.filterApps);
+
+      // Prompt the user to pick an app.  If they pick one, and it's a valid
+      // selection, then add it to the list of possible handlers.
+      fp.open(rv => {
+        if (rv == nsIFilePicker.returnOK && fp.file &&
+            this._isValidHandlerExecutable(fp.file)) {
+          handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
+                         .createInstance(Ci.nsILocalHandlerApp);
+          handlerApp.name = getDisplayNameForFile(fp.file);
+          handlerApp.executable = fp.file;
+
+          // Add the app to the type's list of possible handlers.
+          let handlerInfo = this._handledTypes[this._list.selectedItem.type];
+          handlerInfo.addPossibleApplicationHandler(handlerApp);
+        }
+        onSelectionDone();
+      });
     }
   },
 
   _setIconClassForPreferredAction: function(aHandlerInfo, aElement) {
     // If this returns true, the attribute that CSS sniffs for was set to something
     // so you shouldn't manually set an icon URI.
     // This removes the existing actionIcon attribute if any, even if returning false.
     aElement.removeAttribute("actionIcon");
--- a/suite/common/pref/pref-cache.js
+++ b/suite/common/pref/pref-cache.js
@@ -52,37 +52,41 @@ function ReadCacheFolder(aField)
     {
       // no disk cache folder pref set; default to profile directory
       file = GetSpecialDirectory(Services.dirsvc.has("ProfLD") ? "ProfLD"
                                                                : "ProfD");
     }
     catch (ex) {}
   }
 
-  if (file)
-  {
+  if (file) {
     aField.file = file;
     aField.label = (/Mac/.test(navigator.platform)) ? file.leafName : file.path;
   }
 }
 
 function CacheSelectFolder()
 {
-  var pref = document.getElementById("browser.cache.disk.parent_directory");
   const nsIFilePicker = Ci.nsIFilePicker;
-  var fp = Cc["@mozilla.org/filepicker;1"]
+  let fp = Cc["@mozilla.org/filepicker;1"]
              .createInstance(nsIFilePicker);
-  var prefutilitiesBundle = document.getElementById("bundle_prefutilities");
-  var title = prefutilitiesBundle.getString("cachefolder");
+  let title = document.getElementById("bundle_prefutilities")
+                      .getString("cachefolder");
 
   fp.init(window, title, nsIFilePicker.modeGetFolder);
-  fp.displayDirectory = pref.value;
+  fp.displayDirectory = 
+    document.getElementById("browser.cache.disk.parent_directory").value;
   fp.appendFilters(nsIFilePicker.filterAll);
-  if (fp.show() == nsIFilePicker.returnOK)
-    pref.value = fp.file;
+
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK || !fp.file) {
+      return;
+    }
+    document.getElementById("browser.cache.disk.parent_directory").value = fp.file;
+  });
 }
 
 function ClearDiskAndMemCache()
 {
   Cc["@mozilla.org/netwerk/cache-storage-service;1"]
     .getService(Ci.nsICacheStorageService).clear();
   updateActualCacheSize();
 }
--- a/suite/common/pref/pref-download.js
+++ b/suite/common/pref/pref-download.js
@@ -40,36 +40,38 @@ function ReadUseDownloadDir()
 /**
   * Displays a file picker in which the user can choose the location where
   * downloads are automatically saved, updating preferences and UI in
   * response to the choice, if one is made.
   */
 function ChooseFolder()
 {
   const nsIFilePicker = Ci.nsIFilePicker;
-
-  var fp = Cc["@mozilla.org/filepicker;1"]
+  let fp = Cc["@mozilla.org/filepicker;1"]
              .createInstance(nsIFilePicker);
-  var prefutilitiesBundle = document.getElementById("bundle_prefutilities");
-  var title = prefutilitiesBundle.getString("downloadfolder");
+  let title = document.getElementById("bundle_prefutilities")
+                      .getString("downloadfolder");
   fp.init(window, title, nsIFilePicker.modeGetFolder);
   fp.appendFilters(nsIFilePicker.filterAll);
 
-  var folderListPref = document.getElementById("browser.download.folderList");
-  fp.displayDirectory = IndexToFolder(folderListPref.value); // file
-
-  if (fp.show() == nsIFilePicker.returnOK) {
-    var currentDirPref = document.getElementById("browser.download.dir");
-    currentDirPref.value = fp.file;
-    folderListPref.value = FolderToIndex(fp.file);
+  fp.displayDirectory = 
+    IndexToFolder(document.getElementById("browser.download.folderList")
+                          .value);
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK || !fp.file) {
+      return;
+    }
+    document.getElementById("browser.download.dir").value = fp.file;
+    document.getElementById("browser.download.folderList").value = 
+      FolderToIndex(fp.file);
     // Note, the real prefs will not be updated yet, so dnld manager's
     // userDownloadsDirectory may not return the right folder after
     // this code executes. displayDownloadDirPref will be called on
     // the assignment above to update the UI.
-  }
+  });
 }
 
 /**
   * Initializes the download folder display settings based on the user's
   * preferences.
   */
 function DisplayDownloadDirPref()
 {
--- a/suite/common/pref/pref-navigator.js
+++ b/suite/common/pref/pref-navigator.js
@@ -196,29 +196,33 @@ function UpdateHomePageList(aSingleURL)
   // write single URL into input box and set it as the list of homepages
   SetHomePageValue(aSingleURL);
   UpdateHomePageListFromInput();
 }
 
 function SelectFile()
 {
   const nsIFilePicker = Ci.nsIFilePicker;
-  var fp = Cc["@mozilla.org/filepicker;1"]
+  let fp = Cc["@mozilla.org/filepicker;1"]
              .createInstance(nsIFilePicker);
-  var prefutilitiesBundle = document.getElementById("bundle_prefutilities");
-  var title = prefutilitiesBundle.getString("choosehomepage");
+  let title = document.getElementById("bundle_prefutilities")
+                      .getString("choosehomepage");
   fp.init(window, title, nsIFilePicker.modeOpen);
   fp.appendFilters(nsIFilePicker.filterAll  |
                    nsIFilePicker.filterText |
                    nsIFilePicker.filterXML  |
                    nsIFilePicker.filterHTML |
                    nsIFilePicker.filterImages);
 
-  if (fp.show() == nsIFilePicker.returnOK)
-    UpdateHomePageList(fp.fileURL.spec);
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK && fp.fileURL.spec && 
+        fp.fileURL.spec.length > 0) {
+      UpdateHomePageList(fp.fileURL.spec);
+    }
+  });
 }
 
 function SetHomePageToCurrentPage()
 {
   UpdateHomePageList(GetCurrentPage());
 }
 
 function SetHomePageToCurrentGroup()
--- a/suite/common/pref/preferences.js
+++ b/suite/common/pref/preferences.js
@@ -1,16 +1,18 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // The content of this file is loaded into the scope of the
 // prefwindow and will be available to all prefpanes!
 
+ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+
 function OnLoad()
 {
   // Make sure that the preferences window fits the screen.
   let dialog    = document.documentElement;
   let curHeight = dialog.scrollHeight;
   let curWidth  = dialog.scrollWidth;
 
   // Leave some space for desktop toolbar and window decoration.
@@ -45,49 +47,54 @@ function EnableElement(aElement, aEnable
 }
 
 function WriteSoundField(aField, aValue)
 {
   var file = GetFileFromString(aValue);
   if (file)
   {
     aField.file = file;
-    aField.label = (/Mac/.test(navigator.platform)) ? file.leafName : file.path;
+    aField.label = (AppConstants.platform == "macosx") ? file.leafName : file.path;
   }
 }
 
 function SelectSound(aSoundUrlPref)
 {
+  var soundUrlPref = aSoundUrlPref;
   const nsIFilePicker = Ci.nsIFilePicker;
-  var fp = Cc["@mozilla.org/filepicker;1"]
+  let fp = Cc["@mozilla.org/filepicker;1"]
              .createInstance(nsIFilePicker);
   var prefutilitiesBundle = document.getElementById("bundle_prefutilities");
   fp.init(window, prefutilitiesBundle.getString("choosesound"),
           nsIFilePicker.modeOpen);
 
-  var file = GetFileFromString(aSoundUrlPref.value);
+  let file = GetFileFromString(soundUrlPref.value);
   if (file && file.parent && file.parent.exists())
     fp.displayDirectory = file.parent;
 
-  var filterExts = "*.wav; *.wave";
+  let filterExts = "*.wav; *.wave";
   // On Mac, allow AIFF and CAF files too.
-  if (/Mac/.test(navigator.platform))
+  if (AppConstants.platform == "macosx") {
     filterExts += "; *.aif; *.aiff; *.caf";
+  }
   fp.appendFilter(prefutilitiesBundle.getString("SoundFiles"), filterExts);
   fp.appendFilters(nsIFilePicker.filterAll);
-
-  if (fp.show() == nsIFilePicker.returnOK)
-    aSoundUrlPref.value = fp.fileURL.spec;
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK && fp.fileURL.spec && 
+        fp.fileURL.spec.length > 0) {
+      soundUrlPref.value = fp.fileURL.spec;
+    }
+  });
 }
 
 function PlaySound(aValue, aMail)
 {
   const nsISound = Ci.nsISound;
   var sound = Cc["@mozilla.org/sound;1"]
                 .createInstance(nsISound);
 
   if (aValue)
     sound.play(Services.io.newURI(aValue));
-  else if (aMail && !/Mac/.test(navigator.platform))
+  else if (aMail && (AppConstants.platform != "macosx"))
     sound.playEventSound(nsISound.EVENT_NEW_MAIL_RECEIVED);
   else
     sound.beep();
 }
--- a/suite/common/sync/syncUtils.js
+++ b/suite/common/sync/syncUtils.js
@@ -150,36 +150,38 @@ var gSyncUtils = {
    * Save passphrase backup document to disk as HTML file.
    *
    * @param elid : ID of the form element containing the passphrase.
    */
   passphraseSave: function(elid) {
     let dialogTitle = this._stringBundle.GetStringFromName("save.recoverykey.title");
     let defaultSaveName = this._stringBundle.GetStringFromName("save.recoverykey.defaultfilename");
     this._preparePPiframe(elid, function(iframe) {
-      let filepicker = Cc["@mozilla.org/filepicker;1"]
-                         .createInstance(Ci.nsIFilePicker);
-      filepicker.init(window, dialogTitle, Ci.nsIFilePicker.modeSave);
-      filepicker.appendFilters(Ci.nsIFilePicker.filterHTML);
-      filepicker.defaultString = defaultSaveName;
-      let rv = filepicker.show();
-      if (rv == Ci.nsIFilePicker.returnOK
-          || rv == Ci.nsIFilePicker.returnReplace) {
-        let stream = Cc["@mozilla.org/network/file-output-stream;1"]
-                       .createInstance(Ci.nsIFileOutputStream);
-        stream.init(filepicker.file, -1, parseInt("0600", 8), 0);
+      let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+      let fpCallback = function fpCallback_done(aResult) {
+        if (aResult == Ci.nsIFilePicker.returnOK ||
+            aResult == Ci.nsIFilePicker.returnReplace) {
+          let stream = Cc["@mozilla.org/network/file-output-stream;1"]
+                         .createInstance(Ci.nsIFileOutputStream);
+          stream.init(filepicker.file, -1, parseInt("0600", 8), 0);
 
-        let serializer = new XMLSerializer();
-        let output = serializer.serializeToString(iframe.contentDocument);
-        output = output.replace(/<!DOCTYPE (.|\n)*?]>/,
-          '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
-          '"DTD/xhtml1-strict.dtd">');
-        output = Weave.Utils.encodeUTF8(output);
-        stream.write(output, output.length);
-      }
+          let serializer = new XMLSerializer();
+          let output = serializer.serializeToString(iframe.contentDocument);
+          output = output.replace(/<!DOCTYPE (.|\n)*?]>/,
+            '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
+            '"DTD/xhtml1-strict.dtd">');
+          output = Weave.Utils.encodeUTF8(output);
+          stream.write(output, output.length);
+        }
+      };
+
+      fp.init(window, dialogTitle, Ci.nsIFilePicker.modeSave);
+      fp.appendFilters(Ci.nsIFilePicker.filterHTML);
+      fp.defaultString = defaultSaveName;
+      fp.open(fpCallback);
       return false;
     });
   },
 
   /**
    * validatePassword
    *
    * @param el1 : the first textbox element in the form
--- a/suite/components/feeds/FeedWriter.js
+++ b/suite/components/feeds/FeedWriter.js
@@ -636,47 +636,53 @@ FeedWriter.prototype = {
    */
   _getUIElement: function getUIElement(id) {
     return this._document.getAnonymousElementByAttribute(
       this._document.getElementById("feedSubscribeLine"), "anonid", id);
   },
 
   /**
    * Displays a prompt from which the user may choose a (client) feed reader.
-   * @return - true if a feed reader was selected, false otherwise.
+   * @param aCallback the callback method, passes in true if a feed reader was
+   *        selected, false otherwise.
    */
-  _chooseClientApp: function chooseClientApp() {
+  _chooseClientApp: function chooseClientApp(aCallback) {
     try {
-      var fp = Cc["@mozilla.org/filepicker;1"]
+      let fp = Cc["@mozilla.org/filepicker;1"]
                  .createInstance(Ci.nsIFilePicker);
+      let fpCallback = function fpCallback_done(aResult) {
+        if (aResult == Ci.nsIFilePicker.returnOK) {
+          this._selectedApp = fp.file;
+          if (this._selectedApp) {
+            let file = Services.dirsvc.get("XREExeF", Ci.nsIFile);
+            if (fp.file.leafName != file.leafName) {
+              this._initMenuItemWithFile(this._selectedAppMenuItem,
+                                         this._selectedApp);
+
+              // Show and select the selected application menuitem
+              this._selectedAppMenuItem.hidden = false;
+              this._selectedAppMenuItem.doCommand();
+              if (aCallback) {
+                aCallback(true);
+                return;
+              }
+            }
+          }
+        }
+        if (aCallback) {
+          aCallback(false);
+        }
+      }.bind(this);
+
       fp.init(this._window,
               this._getString("chooseApplicationDialogTitle"),
               Ci.nsIFilePicker.modeOpen);
       fp.appendFilters(Ci.nsIFilePicker.filterApps);
-
-      if (fp.show() == Ci.nsIFilePicker.returnOK) {
-        this._selectedApp = fp.file;
-        if (this._selectedApp) {
-          var file = Services.dirsvc.get("XREExeF", Ci.nsIFile);
-          if (fp.file.leafName != file.leafName) {
-            this._initMenuItemWithFile(this._selectedAppMenuItem,
-                                       this._selectedApp);
-
-            // Show and select the selected application menuitem
-            this._selectedAppMenuItem.hidden = false;
-            this._selectedAppMenuItem.doCommand();
-            return true;
-          }
-        }
-      }
-    }
-    catch(ex) {
-    }
-
-    return false;
+      fp.open(fpCallback);
+    } catch(ex) {}
   },
 
   _setAlwaysUseCheckedState: function setAlwaysUseCheckedState(feedType) {
     var checkbox = this._getUIElement("alwaysUse");
     if (checkbox) {
       var alwaysUse = (safeGetCharPref(getPrefActionForType(feedType), "ask") != "ask");
       this._setCheckboxCheckedState(checkbox, alwaysUse);
     }
@@ -742,20 +748,24 @@ FeedWriter.prototype = {
            * Application" item is being selected with the keyboard. We do this
            * by ignoring command events while the dropdown is closed (user
            * arrowing through the combobox), but handling them while the
            * combobox dropdown is open (user pressed enter when an item was
            * selected). If we don't show the filepicker here, it will be shown
            * when clicking "Subscribe Now".
            */
           var popupbox = this._handlersMenuList.firstChild.boxObject;
-          if (popupbox.popupState == "hiding" && !this._chooseClientApp()) {
-            // Select the (per-prefs) selected handler if no application was
-            // selected
-            this._setSelectedHandler(this._getFeedType());
+          if (popupbox.popupState == "hiding") {
+            this._chooseClientApp(function(aResult) {
+              if (!aResult) {
+                // Select the (per-prefs) selected handler if no application
+                // was selected
+                this._setSelectedHandler(this._getFeedType());
+              }
+            }.bind(this));
           }
           break;
         default:
           this._setAlwaysUseLabel();
       }
     }
   },
 
@@ -1099,80 +1109,87 @@ FeedWriter.prototype = {
   _subscribe: function subscribe() {
     var feedType = this._getFeedType();
 
     // Subscribe to the feed using the selected handler and save prefs
     var defaultHandler = "reader";
     var useAsDefault = this._getUIElement("alwaysUse").getAttribute("checked");
 
     var selectedItem = this._getSelectedItemFromMenulist(this._handlersMenuList);
+    let subscribeCallback = function() {
+      if (selectedItem.hasAttribute("webhandlerurl")) {
+        var webURI = selectedItem.getAttribute("webhandlerurl");
+        Services.prefs.setCharPref(getPrefReaderForType(feedType), "web");
+
+        Services.prefs.setStringPref(getPrefWebForType(feedType), webURI);
+
+        var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]
+                     .getService(Ci.nsIWebContentConverterService);
+        var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI);
+        if (handler) {
+          if (useAsDefault)
+            wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler);
+
+          this._window.location.href = handler.getHandlerURI(this._window.location.href);
+        }
+      }
+      else {
+        switch (selectedItem.getAttribute("anonid")) {
+          case "selectedAppMenuItem":
+            Services.prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsIFile,
+                                           this._selectedApp);
+            Services.prefs.setCharPref(getPrefReaderForType(feedType), "client");
+            break;
+          case "defaultHandlerMenuItem":
+            Services.prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsIFile,
+                                           this._defaultSystemReader);
+            Services.prefs.setCharPref(getPrefReaderForType(feedType), "client");
+            break;
+          case "liveBookmarksMenuItem":
+            defaultHandler = "bookmarks";
+            Services.prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks");
+            break;
+          case "messengerFeedsMenuItem":
+            defaultHandler = "messenger";
+            Services.prefs.setCharPref(getPrefReaderForType(feedType), "messenger");
+            break;
+        }
+        var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"]
+                            .getService(Ci.nsIFeedResultService);
+
+        // Pull the title and subtitle out of the document
+        var feedTitle = this._document.getElementById(TITLE_ID).textContent;
+        var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent;
+        feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType);
+      }
+
+      // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
+      // to either "reader" (If a web reader or if an application is selected),
+      // or to "messenger" (if the messenger feeds option is selected).
+      // Otherwise, we should set it to "ask"
+      if (useAsDefault) {
+        Services.prefs.setCharPref(getPrefActionForType(feedType), defaultHandler);
+      } else {
+        Services.prefs.setCharPref(getPrefActionForType(feedType), "ask");
+      }
+    }.bind(this);
 
     // Show the file picker before subscribing if the
     // choose application menuitem was chosen using the keyboard
     if (selectedItem.getAttribute("anonid") == "chooseApplicationMenuItem") {
-      if (!this._chooseClientApp())
-        return;
-
-      selectedItem = this._getSelectedItemFromMenulist(this._handlersMenuList);
-    }
-
-    if (selectedItem.hasAttribute("webhandlerurl")) {
-      var webURI = selectedItem.getAttribute("webhandlerurl");
-      Services.prefs.setCharPref(getPrefReaderForType(feedType), "web");
-
-      Services.prefs.setStringPref(getPrefWebForType(feedType), webURI);
-
-      var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]
-                   .getService(Ci.nsIWebContentConverterService);
-      var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI);
-      if (handler) {
-        if (useAsDefault)
-          wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler);
-
-        this._window.location.href = handler.getHandlerURI(this._window.location.href);
-      }
+      this._chooseClientApp(function(aResult) {
+        if (aResult) {
+          selectedItem =
+            this._getSelectedItemFromMenulist(this._handlersMenuList);
+          subscribeCallback();
+        }
+      }.bind(this));
+    } else {
+      subscribeCallback();
     }
-    else {
-      switch (selectedItem.getAttribute("anonid")) {
-        case "selectedAppMenuItem":
-          Services.prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsIFile,
-                                         this._selectedApp);
-          Services.prefs.setCharPref(getPrefReaderForType(feedType), "client");
-          break;
-        case "defaultHandlerMenuItem":
-          Services.prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsIFile,
-                                         this._defaultSystemReader);
-          Services.prefs.setCharPref(getPrefReaderForType(feedType), "client");
-          break;
-        case "liveBookmarksMenuItem":
-          defaultHandler = "bookmarks";
-          Services.prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks");
-          break;
-        case "messengerFeedsMenuItem":
-          defaultHandler = "messenger";
-          Services.prefs.setCharPref(getPrefReaderForType(feedType), "messenger");
-          break;
-      }
-      var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"]
-                          .getService(Ci.nsIFeedResultService);
-
-      // Pull the title and subtitle out of the document
-      var feedTitle = this._document.getElementById(TITLE_ID).textContent;
-      var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent;
-      feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType);
-    }
-
-    // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
-    // to either "reader" (If a web reader or if an application is selected),
-    // or to "messenger" (if the messenger feeds option is selected).
-    // Otherwise, we should set it to "ask"
-    if (useAsDefault)
-      Services.prefs.setCharPref(getPrefActionForType(feedType), defaultHandler);
-    else
-      Services.prefs.setCharPref(getPrefActionForType(feedType), "ask");
   },
 
   // nsIObserver
   observe: function observe(subject, topic, data) {
     if (!this._window) {
       // this._window is null unless this.init was called with a trusted
       // window object.
       return;
--- a/suite/mailnews/addrbook/abCardOverlay.js
+++ b/suite/mailnews/addrbook/abCardOverlay.js
@@ -929,35 +929,34 @@ function removePhoto(aName) {
   catch (e) {}
   return false;
 }
 
 /**
  * Opens a file picker with image filters to look for a contact photo.
  * If the user selects a file and clicks OK then the PhotoURI textbox is set
  * with a file URI pointing to that file and updatePhoto is called.
- *
- * @return true if the OK button was clicked and a photo was chosen
  */
 function browsePhoto() {
-  var nsIFilePicker = Ci.nsIFilePicker;
-  var fp = Cc["@mozilla.org/filepicker;1"]
-	                   .createInstance(nsIFilePicker);
+  let nsIFilePicker = Ci.nsIFilePicker;
+  let fp = Cc["@mozilla.org/filepicker;1"]
+             .createInstance(nsIFilePicker);
   fp.init(window, gAddressBookBundle.getString("browsePhoto"), nsIFilePicker.modeOpen);
 
   // Add All Files & Image Files filters and select the latter
   fp.appendFilters(nsIFilePicker.filterImages);
   fp.appendFilters(nsIFilePicker.filterAll);
 
-  if (fp.show() == nsIFilePicker.returnOK) {
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK) {
+      return;
+    }
     document.getElementById("PhotoFile").file = fp.file;
     onSwitchPhotoType(document.getElementById("FilePhotoType").value);
-    return true;
-  }
-  return false;
+  });
 }
 
 /* A photo handler defines the behaviour of the contact editor
  * for a particular photo type. Each photo handler must implement
  * the following interface:
  *
  * onLoad: function(aCard, aDocument):
  *   Called when the editor wants to populate the contact editor
--- a/suite/mailnews/compose/MsgComposeCommands.js
+++ b/suite/mailnews/compose/MsgComposeCommands.js
@@ -2403,34 +2403,40 @@ function SetLastAttachDirectory(attached
   catch (ex) {
     dump("error: SetLastAttachDirectory failed: " + ex + "\n");
   }
 }
 
 function AttachFile()
 {
   //Get file using nsIFilePicker and convert to URL
-  try {
-      var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
-      fp.init(window, sComposeMsgsBundle.getString("chooseFileToAttach"), nsIFilePicker.modeOpenMultiple);
-
-      var lastDirectory = GetLocalFilePref(kComposeAttachDirPrefName);
-      if (lastDirectory)
-        fp.displayDirectory = lastDirectory;
-
-      fp.appendFilters(nsIFilePicker.filterAll);
-      if (fp.show() == nsIFilePicker.returnOK) {
-        var firstAttachedFile = AttachFiles(fp.files);
-        if (firstAttachedFile)
-          SetLastAttachDirectory(firstAttachedFile);
+  const nsIFilePicker = Ci.nsIFilePicker;
+  let fp = Cc["@mozilla.org/filepicker;1"]
+             .createInstance(nsIFilePicker);
+  fp.init(window, sComposeMsgsBundle.getString("chooseFileToAttach"),
+          nsIFilePicker.modeOpenMultiple);
+  let lastDirectory = GetLocalFilePref(kComposeAttachDirPrefName);
+  if (lastDirectory)
+    fp.displayDirectory = lastDirectory;
+
+  fp.appendFilters(nsIFilePicker.filterAll);
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK || !fp.files) {
+      return;
+    }
+    try {
+      let firstAttachedFile = AttachFiles(fp.files);
+      if (firstAttachedFile) {
+        SetLastAttachDirectory(firstAttachedFile);
       }
-  }
-  catch (ex) {
-    dump("failed to get attachments: " + ex + "\n");
-  }
+    }
+    catch (ex) {
+      dump("failed to get attachments: " + ex + "\n");
+    }
+  });
 }
 
 function AttachFiles(attachments)
 {
   if (!attachments || !attachments.hasMoreElements())
     return null;
 
   var firstAttachedFile = null;
--- a/suite/mailnews/mailWindowOverlay.js
+++ b/suite/mailnews/mailWindowOverlay.js
@@ -1578,45 +1578,41 @@ function MsgSaveAsFile()
   SaveAsFile(gFolderDisplay.selectedMessageUris);
 }
 
 function MsgSaveAsTemplate()
 {
   SaveAsTemplate(gFolderDisplay.selectedMessageUris);
 }
 
-const nsIFilePicker = Ci.nsIFilePicker;
-
 function MsgOpenFromFile()
 {
-   var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+  const nsIFilePicker = Ci.nsIFilePicker;
+  var fp = Cc["@mozilla.org/filepicker;1"]
+             .createInstance(nsIFilePicker);
 
   var filterLabel = gMessengerBundle.getString("EMLFiles");
   var windowTitle = gMessengerBundle.getString("OpenEMLFiles");
 
-   fp.init(window, windowTitle, nsIFilePicker.modeOpen);
-   fp.appendFilter(filterLabel, "*.eml; *.msg");
-
-   // Default or last filter is "All Files"
-   fp.appendFilters(nsIFilePicker.filterAll);
-
-  try {
-     var ret = fp.show();
-     if (ret == nsIFilePicker.returnCancel)
-       return;
-   }
-   catch (ex) {
-     dump("filePicker.chooseInputFile threw an exception\n");
-     return;
-   }
-
-  var uri = fp.fileURL.QueryInterface(Ci.nsIURL);
-  uri.query = "type=application/x-message-display";
-
-  window.openDialog( "chrome://messenger/content/messageWindow.xul", "_blank", "all,chrome,dialog=no,status,toolbar", uri, null, null );
+  fp.init(window, windowTitle, nsIFilePicker.modeOpen);
+  fp.appendFilter(filterLabel, "*.eml; *.msg");
+
+  // Default or last filter is "All Files".
+  fp.appendFilters(nsIFilePicker.filterAll);
+
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK || !fp.file) {
+      return;
+    }
+    let uri = fp.fileURL.QueryInterface(Ci.nsIURL);
+    uri.query = "type=application/x-message-display";
+
+    window.openDialog("chrome://messenger/content/messageWindow.xul", "_blank",
+                    "all,chrome,dialog=no,status,toolbar", uri);
+  });
 }
 
 function MsgOpenNewWindowForMsgHdr(hdr)
 {
   MsgOpenNewWindowForFolder(hdr.folder.URI, hdr.messageKey);
 }
 
 function MsgOpenNewWindowForFolder(uri, key)