Bug 1129873 - [GTK3] Implement wrapper to GtkAppChooserDialog to allow using native application chooser. r=karlt
authorJan Horak <jhorak@redhat.com>
Mon, 08 Jun 2015 04:41:00 -0400
changeset 247615 e68096bfbf3962aa8ed5d7e87942d70d896a2efb
parent 247614 a6f9a20a2bccc66386231a07e1849ec0307778c0
child 247616 e637319144d3906ef28aa51348de900e49c79c56
push id28874
push userryanvm@gmail.com
push dateTue, 09 Jun 2015 16:52:27 +0000
treeherdermozilla-central@76ae244b637a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1129873
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1129873 - [GTK3] Implement wrapper to GtkAppChooserDialog to allow using native application chooser. r=karlt
toolkit/mozapps/downloads/nsHelperAppDlg.js
widget/gtk/moz.build
widget/gtk/mozgtk/mozgtk.c
widget/gtk/nsApplicationChooser.cpp
widget/gtk/nsApplicationChooser.h
widget/gtk/nsWidgetFactory.cpp
widget/moz.build
widget/nsIApplicationChooser.idl
widget/nsWidgetsCID.h
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -999,16 +999,44 @@ nsUnknownContentTypeDialog.prototype = {
       try {
         return file.bundleDisplayName;
       } catch (e) {}
     }
 #endif
     return file.leafName;
   },
 
+  finishChooseApp: function() {
+    if (this.chosenApp) {
+      // Show the "handler" menulist since we have a (user-specified)
+      // application now.
+      this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
+
+      // Update dialog.
+      var otherHandler = this.dialogElement("otherHandler");
+      otherHandler.removeAttribute("hidden");
+      otherHandler.setAttribute("path", this.getPath(this.chosenApp.executable));
+#ifdef XP_WIN
+      otherHandler.label = this.getFileDisplayName(this.chosenApp.executable);
+#else
+      otherHandler.label = this.chosenApp.name;
+#endif
+      this.dialogElement("openHandler").selectedIndex = 1;
+      this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
+
+      this.dialogElement("mode").selectedItem = this.dialogElement("open");
+    }
+    else {
+      var openHandler = this.dialogElement("openHandler");
+      var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
+      if (!lastSelectedID)
+        lastSelectedID = "defaultHandler";
+      openHandler.selectedItem = this.dialogElement(lastSelectedID);
+    }
+  },
   // chooseApp:  Open file picker and prompt user for application.
   chooseApp: function() {
 #ifdef XP_WIN
     // Protect against the lack of an extension
     var fileExtension = "";
     try {
       fileExtension = this.mLauncher.MIMEInfo.primaryExtension;
     } catch(ex) {
@@ -1042,17 +1070,33 @@ nsUnknownContentTypeDialog.prototype = {
                             "chrome,modal,centerscreen,titlebar,dialog=yes",
                             params);
 
     if (params.handlerApp &&
         params.handlerApp.executable &&
         params.handlerApp.executable.isFile()) {
       // Remember the file they chose to run.
       this.chosenApp = params.handlerApp;
-
+    }
+#else
+#if MOZ_WIDGET_GTK == 3
+    var nsIApplicationChooser = Components.interfaces.nsIApplicationChooser;
+    var appChooser = Components.classes["@mozilla.org/applicationchooser;1"]
+                               .createInstance(nsIApplicationChooser);
+    appChooser.init(this.mDialog, this.dialogElement("strings").getString("chooseAppFilePickerTitle"));
+    var contentTypeDialogObj = this;
+    let appChooserCallback = function appChooserCallback_done(aResult) {
+      if (aResult) {
+         contentTypeDialogObj.chosenApp = aResult.QueryInterface(Components.interfaces.nsILocalHandlerApp);
+      }
+      contentTypeDialogObj.finishChooseApp();
+    };
+    appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback);
+    // The finishChooseApp is called from appChooserCallback
+    return;
 #else
     var nsIFilePicker = Components.interfaces.nsIFilePicker;
     var fp = Components.classes["@mozilla.org/filepicker;1"]
                        .createInstance(nsIFilePicker);
     fp.init(this.mDialog,
             this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
             nsIFilePicker.modeOpen);
 
@@ -1060,39 +1104,21 @@ nsUnknownContentTypeDialog.prototype = {
 
     if (fp.show() == nsIFilePicker.returnOK && fp.file) {
       // Remember the file they chose to run.
       var localHandlerApp =
         Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
                    createInstance(Components.interfaces.nsILocalHandlerApp);
       localHandlerApp.executable = fp.file;
       this.chosenApp = localHandlerApp;
-#endif
-
-      // Show the "handler" menulist since we have a (user-specified)
-      // application now.
-      this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
+    }
+#endif // MOZ_WIDGET_GTK3
 
-      // Update dialog.
-      var otherHandler = this.dialogElement("otherHandler");
-      otherHandler.removeAttribute("hidden");
-      otherHandler.setAttribute("path", this.getPath(this.chosenApp.executable));
-      otherHandler.label = this.getFileDisplayName(this.chosenApp.executable);
-      this.dialogElement("openHandler").selectedIndex = 1;
-      this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
-
-      this.dialogElement("mode").selectedItem = this.dialogElement("open");
-    }
-    else {
-      var openHandler = this.dialogElement("openHandler");
-      var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
-      if (!lastSelectedID)
-        lastSelectedID = "defaultHandler";
-      openHandler.selectedItem = this.dialogElement(lastSelectedID);
-    }
+#endif // XP_WIN
+    this.finishChooseApp();
   },
 
   // Turn this on to get debugging messages.
   debug: false,
 
   // Dump text (if debug is on).
   dump: function( text ) {
     if ( this.debug ) {
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -69,16 +69,17 @@ if CONFIG['ACCESSIBILITY']:
 
 if CONFIG['MOZ_ENABLE_GTK2']:
     UNIFIED_SOURCES += [
         'gtk2drawing.c',
     ]
 else:
     UNIFIED_SOURCES += [
         'gtk3drawing.c',
+        'nsApplicationChooser.cpp',
     ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/layout/generic',
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -535,16 +535,21 @@ STUB(gtk_style_context_save)
 STUB(gtk_style_context_set_path)
 STUB(gtk_style_context_set_state)
 STUB(gtk_tree_view_column_get_button)
 STUB(gtk_widget_get_preferred_size)
 STUB(gtk_widget_get_style_context)
 STUB(gtk_widget_path_append_type)
 STUB(gtk_widget_path_new)
 STUB(gtk_widget_set_visual)
+STUB(gtk_app_chooser_dialog_new_for_content_type)
+STUB(gtk_app_chooser_get_type)
+STUB(gtk_app_chooser_get_app_info)
+STUB(gtk_app_chooser_dialog_get_type)
+STUB(gtk_app_chooser_dialog_set_heading)
 #endif
 
 #ifdef GTK2_SYMBOLS
 STUB(gdk_drawable_get_screen)
 STUB(gdk_rgb_get_colormap)
 STUB(gdk_rgb_get_visual)
 STUB(gdk_window_lookup)
 STUB(gdk_window_set_back_pixmap)
new file mode 100644
--- /dev/null
+++ b/widget/gtk/nsApplicationChooser.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; 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/. */
+
+#include "mozilla/Types.h"
+
+#include <gtk/gtk.h>
+
+#include "nsApplicationChooser.h"
+#include "WidgetUtils.h"
+#include "nsIMIMEInfo.h"
+#include "nsCExternalHandlerService.h"
+#include "nsGtkUtils.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(nsApplicationChooser, nsIApplicationChooser)
+
+nsApplicationChooser::nsApplicationChooser()
+{
+}
+
+nsApplicationChooser::~nsApplicationChooser()
+{
+}
+
+NS_IMETHODIMP
+nsApplicationChooser::Init(nsIDOMWindow* aParent, const nsACString& aTitle)
+{
+  NS_ENSURE_TRUE(aParent, NS_ERROR_FAILURE);
+  mParentWidget = widget::WidgetUtils::DOMWindowToWidget(aParent);
+  mWindowTitle.Assign(aTitle);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsApplicationChooser::Open(const nsACString& aContentType, nsIApplicationChooserFinishedCallback *aCallback)
+{
+  MOZ_ASSERT(aCallback);
+  if (mCallback) {
+    NS_WARNING("Chooser is already in progress.");
+    return NS_ERROR_ALREADY_INITIALIZED;
+  }
+  mCallback = aCallback;
+  NS_ENSURE_TRUE(mParentWidget, NS_ERROR_FAILURE);
+  GtkWindow *parent_widget =
+    GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
+
+  GtkWidget* chooser =
+    gtk_app_chooser_dialog_new_for_content_type(parent_widget,
+        (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+        PromiseFlatCString(aContentType).get());
+  gtk_app_chooser_dialog_set_heading(GTK_APP_CHOOSER_DIALOG(chooser), mWindowTitle.BeginReading());
+  NS_ADDREF_THIS();
+  g_signal_connect(chooser, "response", G_CALLBACK(OnResponse), this);
+  g_signal_connect(chooser, "destroy", G_CALLBACK(OnDestroy), this);
+  gtk_widget_show(chooser);
+  return NS_OK;
+}
+
+/* static */ void
+nsApplicationChooser::OnResponse(GtkWidget* chooser, gint response_id, gpointer user_data)
+{
+  static_cast<nsApplicationChooser*>(user_data)->Done(chooser, response_id);
+}
+
+/* static */ void
+nsApplicationChooser::OnDestroy(GtkWidget *chooser, gpointer user_data)
+{
+  static_cast<nsApplicationChooser*>(user_data)->Done(chooser, GTK_RESPONSE_CANCEL);
+}
+
+void nsApplicationChooser::Done(GtkWidget* chooser, gint response)
+{
+  nsCOMPtr<nsILocalHandlerApp> localHandler;
+  nsresult rv;
+  switch (response) {
+    case GTK_RESPONSE_OK:
+    case GTK_RESPONSE_ACCEPT:
+        {
+          localHandler = do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
+          if (NS_FAILED(rv)) {
+            NS_WARNING("Out of memory.");
+            break;
+          }
+          GAppInfo *app_info = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(chooser));
+
+          nsCOMPtr<nsIFile> localExecutable;
+          gchar *fileWithFullPath = g_find_program_in_path(g_app_info_get_executable(app_info));
+          rv = NS_NewNativeLocalFile(nsDependentCString(fileWithFullPath), false, getter_AddRefs(localExecutable));
+          g_free(fileWithFullPath);
+          if (NS_FAILED(rv)) {
+            NS_WARNING("Cannot create local filename.");
+            localHandler = nullptr;
+          } else {
+            localHandler->SetExecutable(localExecutable);
+            localHandler->SetName(NS_ConvertUTF8toUTF16(g_app_info_get_display_name(app_info)));
+          }
+          g_object_unref(app_info);
+        }
+
+        break;
+    case GTK_RESPONSE_CANCEL:
+    case GTK_RESPONSE_CLOSE:
+    case GTK_RESPONSE_DELETE_EVENT:
+        break;
+    default:
+        NS_WARNING("Unexpected response");
+        break;
+  }
+
+  // A "response" signal won't be sent again but "destroy" will be.
+  g_signal_handlers_disconnect_by_func(chooser, FuncToGpointer(OnDestroy), this);
+  gtk_widget_destroy(chooser);
+
+  if (mCallback) {
+    mCallback->Done(localHandler);
+    mCallback = nullptr;
+  }
+  NS_RELEASE_THIS();
+}
+
new file mode 100644
--- /dev/null
+++ b/widget/gtk/nsApplicationChooser.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef nsApplicationChooser_h__
+#define nsApplicationChooser_h__
+
+#include <gtk/gtk.h>
+#include "nsIApplicationChooser.h"
+
+class nsApplicationChooser : public nsIApplicationChooser
+{
+public:
+  nsApplicationChooser();
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIAPPLICATIONCHOOSER
+  void Done(GtkWidget* chooser, gint response);
+
+private:
+  ~nsApplicationChooser();
+  nsCOMPtr<nsIWidget> mParentWidget;
+  nsCString mWindowTitle;
+  nsCOMPtr<nsIApplicationChooserFinishedCallback> mCallback;
+  static void OnResponse(GtkWidget* chooser, gint response_id, gpointer user_data);
+  static void OnDestroy(GtkWidget* chooser, gpointer user_data);
+};
+#endif
--- a/widget/gtk/nsWidgetFactory.cpp
+++ b/widget/gtk/nsWidgetFactory.cpp
@@ -16,16 +16,19 @@
 #include "nsWindow.h"
 #include "nsTransferable.h"
 #include "nsHTMLFormatConverter.h"
 #ifdef MOZ_X11
 #include "nsClipboardHelper.h"
 #include "nsClipboard.h"
 #include "nsDragService.h"
 #endif
+#if (MOZ_WIDGET_GTK == 3)
+#include "nsApplicationChooser.h"
+#endif
 #include "nsColorPicker.h"
 #include "nsFilePicker.h"
 #include "nsSound.h"
 #include "nsBidiKeyboard.h"
 #include "nsScreenManagerGtk.h"
 #include "nsGTKToolkit.h"
 #include "WakeLockListener.h"
 
@@ -147,16 +150,35 @@ nsFilePickerConstructor(nsISupports *aOu
 
   if (!picker) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return picker->QueryInterface(aIID, aResult);
 }
 
+#if (MOZ_WIDGET_GTK == 3)
+static nsresult
+nsApplicationChooserConstructor(nsISupports *aOuter, REFNSIID aIID,
+                                void **aResult)
+{
+  *aResult = nullptr;
+  if (aOuter != nullptr) {
+    return NS_ERROR_NO_AGGREGATION;
+  }
+  nsCOMPtr<nsIApplicationChooser> chooser = new nsApplicationChooser;
+
+  if (!chooser) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return chooser->QueryInterface(aIID, aResult);
+}
+#endif
+
 static nsresult
 nsColorPickerConstructor(nsISupports *aOuter, REFNSIID aIID,
                          void **aResult)
 {
     *aResult = nullptr;
     if (aOuter != nullptr) {
         return NS_ERROR_NO_AGGREGATION;
     }
@@ -170,16 +192,19 @@ nsColorPickerConstructor(nsISupports *aO
     return picker->QueryInterface(aIID, aResult);
 }
 
 NS_DEFINE_NAMED_CID(NS_WINDOW_CID);
 NS_DEFINE_NAMED_CID(NS_CHILD_CID);
 NS_DEFINE_NAMED_CID(NS_APPSHELL_CID);
 NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID);
 NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
+#if (MOZ_WIDGET_GTK == 3)
+NS_DEFINE_NAMED_CID(NS_APPLICATIONCHOOSER_CID);
+#endif
 NS_DEFINE_NAMED_CID(NS_SOUND_CID);
 NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID);
 #ifdef MOZ_X11
 NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_CLIPBOARDHELPER_CID);
 NS_DEFINE_NAMED_CID(NS_DRAGSERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID);
@@ -201,16 +226,19 @@ NS_DEFINE_NAMED_CID(NS_GFXINFO_CID);
 
 
 static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
     { &kNS_WINDOW_CID, false, nullptr, nsWindowConstructor },
     { &kNS_CHILD_CID, false, nullptr, nsChildWindowConstructor },
     { &kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor },
     { &kNS_COLORPICKER_CID, false, nullptr, nsColorPickerConstructor, Module::MAIN_PROCESS_ONLY },
     { &kNS_FILEPICKER_CID, false, nullptr, nsFilePickerConstructor, Module::MAIN_PROCESS_ONLY },
+#if (MOZ_WIDGET_GTK == 3)
+    { &kNS_APPLICATIONCHOOSER_CID, false, nullptr, nsApplicationChooserConstructor, Module::MAIN_PROCESS_ONLY },
+#endif
     { &kNS_SOUND_CID, false, nullptr, nsSoundConstructor, Module::MAIN_PROCESS_ONLY },
     { &kNS_TRANSFERABLE_CID, false, nullptr, nsTransferableConstructor },
 #ifdef MOZ_X11
     { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardConstructor, Module::MAIN_PROCESS_ONLY },
     { &kNS_CLIPBOARDHELPER_CID, false, nullptr, nsClipboardHelperConstructor },
     { &kNS_DRAGSERVICE_CID, false, nullptr, nsDragServiceConstructor, Module::MAIN_PROCESS_ONLY },
 #endif
     { &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor },
@@ -234,16 +262,19 @@ static const mozilla::Module::CIDEntry k
 };
 
 static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
     { "@mozilla.org/widget/window/gtk;1", &kNS_WINDOW_CID },
     { "@mozilla.org/widgets/child_window/gtk;1", &kNS_CHILD_CID },
     { "@mozilla.org/widget/appshell/gtk;1", &kNS_APPSHELL_CID },
     { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::MAIN_PROCESS_ONLY },
     { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::MAIN_PROCESS_ONLY },
+#if (MOZ_WIDGET_GTK == 3)
+    { "@mozilla.org/applicationchooser;1", &kNS_APPLICATIONCHOOSER_CID, Module::MAIN_PROCESS_ONLY },
+#endif
     { "@mozilla.org/sound;1", &kNS_SOUND_CID, Module::MAIN_PROCESS_ONLY },
     { "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID },
 #ifdef MOZ_X11
     { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID, Module::MAIN_PROCESS_ONLY },
     { "@mozilla.org/widget/clipboardhelper;1", &kNS_CLIPBOARDHELPER_CID },
     { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID, Module::MAIN_PROCESS_ONLY },
 #endif
     { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID },
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -205,16 +205,20 @@ if toolkit in ('qt', 'gtk2', 'gtk3', 'co
     UNIFIED_SOURCES += [
         'nsBaseFilePicker.cpp',
     ]
 
 if toolkit in ('qt', 'gtk2', 'gtk3', 'windows', 'cocoa'):
     UNIFIED_SOURCES += [
         'nsNativeTheme.cpp',
     ]
+if toolkit == 'gtk3':
+    XPIDL_SOURCES += [
+        'nsIApplicationChooser.idl',
+    ]
 
 if not CONFIG['MOZ_B2G']:
     DEFINES['MOZ_CROSS_PROCESS_IME'] = True
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
new file mode 100644
--- /dev/null
+++ b/widget/nsIApplicationChooser.idl
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; 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/. */
+
+#include "nsISupports.idl"
+#include "nsIMIMEInfo.idl"
+interface nsIDOMWindow;
+
+[scriptable, function, uuid(8144404d-e6c7-4861-bcca-47de912ee811)]
+interface nsIApplicationChooserFinishedCallback : nsISupports
+{
+  void done(in nsIHandlerApp handlerApp);
+};
+
+[scriptable, uuid(8413fc42-d6c4-4d78-bf70-64cd78ebcc5c)]
+interface nsIApplicationChooser : nsISupports
+{
+ /**
+  * Initialize the application chooser picker widget.  The application chooser
+  * is not valid until this method is called.
+  *
+  * @param      parent   nsIDOMWindow parent.  This dialog will be dependent
+  *                      on this parent. parent must be non-null.
+  * @param      title    The title for the file widget
+  *
+  */
+  void init(in nsIDOMWindow parent, in ACString title);
+
+  /**
+   * Open application chooser dialog.
+   *
+   * @param    contentType   content type of file to open
+   * @param    applicationChooserFinishedCallback  callback fuction to run when dialog is closed
+   */
+  void open(in ACString contentType, in nsIApplicationChooserFinishedCallback applicationChooserFinishedCallback);
+};
+
--- a/widget/nsWidgetsCID.h
+++ b/widget/nsWidgetsCID.h
@@ -19,16 +19,21 @@
 { 0xba7de611, 0x6088, 0x11d3,  \
     { 0xa8, 0x3e, 0x0, 0x10, 0x5a, 0x18, 0x34, 0x19 } }
 
 /* bd57cee8-1dd1-11b2-9fe7-95cf4709aea3 */
 #define NS_FILEPICKER_CID \
 { 0xbd57cee8, 0x1dd1, 0x11b2, \
     {0x9f, 0xe7, 0x95, 0xcf, 0x47, 0x09, 0xae, 0xa3} }
 
+/* e221df9b-3d66-4045-9a66-5720949f8d10 */
+#define NS_APPLICATIONCHOOSER_CID \
+{ 0xe221df9b, 0x3d66, 0x4045, \
+    {0x9a, 0x66, 0x57, 0x20, 0x94, 0x9f, 0x8d, 0x10} }
+
 /* 0f872c8c-3ee6-46bd-92a2-69652c6b474e */
 #define NS_COLORPICKER_CID \
 { 0x0f872c8c, 0x3ee6, 0x46bd, \
   { 0x92, 0xa2, 0x69, 0x65, 0x2c, 0x6b, 0x47, 0x4e } }
 
 /* 2d96b3df-c051-11d1-a827-0040959a28c9 */
 #define NS_APPSHELL_CID \
 { 0x2d96b3df, 0xc051, 0x11d1, \