Bug 1869647 - Mark hasStorageAccess.sub.https.window.html as intermittent after wpt...
[gecko.git] / widget / gtk / nsApplicationChooser.cpp
blob6752c52caf54a7a72586296fc2229b3a9dfe70b4
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/Types.h"
8 #include <gtk/gtk.h>
10 #include "nsApplicationChooser.h"
11 #include "WidgetUtils.h"
12 #include "nsIMIMEInfo.h"
13 #include "nsIWidget.h"
14 #include "nsIFile.h"
15 #include "nsCExternalHandlerService.h"
16 #include "nsComponentManagerUtils.h"
17 #include "nsGtkUtils.h"
18 #include "nsPIDOMWindow.h"
20 using namespace mozilla;
22 NS_IMPL_ISUPPORTS(nsApplicationChooser, nsIApplicationChooser)
24 nsApplicationChooser::nsApplicationChooser() = default;
26 nsApplicationChooser::~nsApplicationChooser() = default;
28 NS_IMETHODIMP
29 nsApplicationChooser::Init(mozIDOMWindowProxy* aParent,
30 const nsACString& aTitle) {
31 NS_ENSURE_TRUE(aParent, NS_ERROR_FAILURE);
32 auto* parent = nsPIDOMWindowOuter::From(aParent);
33 mParentWidget = widget::WidgetUtils::DOMWindowToWidget(parent);
34 mWindowTitle.Assign(aTitle);
35 return NS_OK;
38 NS_IMETHODIMP
39 nsApplicationChooser::Open(const nsACString& aContentType,
40 nsIApplicationChooserFinishedCallback* aCallback) {
41 MOZ_ASSERT(aCallback);
42 if (mCallback) {
43 NS_WARNING("Chooser is already in progress.");
44 return NS_ERROR_ALREADY_INITIALIZED;
46 mCallback = aCallback;
47 NS_ENSURE_TRUE(mParentWidget, NS_ERROR_FAILURE);
48 GtkWindow* parent_widget =
49 GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
51 GtkWidget* chooser = gtk_app_chooser_dialog_new_for_content_type(
52 parent_widget,
53 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
54 PromiseFlatCString(aContentType).get());
55 gtk_app_chooser_dialog_set_heading(GTK_APP_CHOOSER_DIALOG(chooser),
56 mWindowTitle.BeginReading());
57 NS_ADDREF_THIS();
58 g_signal_connect(chooser, "response", G_CALLBACK(OnResponse), this);
59 g_signal_connect(chooser, "destroy", G_CALLBACK(OnDestroy), this);
60 gtk_widget_show(chooser);
61 return NS_OK;
64 /* static */
65 void nsApplicationChooser::OnResponse(GtkWidget* chooser, gint response_id,
66 gpointer user_data) {
67 static_cast<nsApplicationChooser*>(user_data)->Done(chooser, response_id);
70 /* static */
71 void nsApplicationChooser::OnDestroy(GtkWidget* chooser, gpointer user_data) {
72 static_cast<nsApplicationChooser*>(user_data)->Done(chooser,
73 GTK_RESPONSE_CANCEL);
76 void nsApplicationChooser::Done(GtkWidget* chooser, gint response) {
77 nsCOMPtr<nsILocalHandlerApp> localHandler;
78 nsresult rv;
79 switch (response) {
80 case GTK_RESPONSE_OK:
81 case GTK_RESPONSE_ACCEPT: {
82 localHandler = do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
83 if (NS_FAILED(rv)) {
84 NS_WARNING("Out of memory.");
85 break;
87 GAppInfo* app_info =
88 gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(chooser));
90 nsCOMPtr<nsIFile> localExecutable;
91 gchar* fileWithFullPath =
92 g_find_program_in_path(g_app_info_get_executable(app_info));
93 if (!fileWithFullPath) {
94 g_object_unref(app_info);
95 NS_WARNING("Cannot find program in path.");
96 break;
98 rv = NS_NewNativeLocalFile(nsDependentCString(fileWithFullPath), false,
99 getter_AddRefs(localExecutable));
100 g_free(fileWithFullPath);
101 if (NS_FAILED(rv)) {
102 NS_WARNING("Cannot create local filename.");
103 localHandler = nullptr;
104 } else {
105 localHandler->SetExecutable(localExecutable);
106 localHandler->SetName(
107 NS_ConvertUTF8toUTF16(g_app_info_get_display_name(app_info)));
109 g_object_unref(app_info);
112 break;
113 case GTK_RESPONSE_CANCEL:
114 case GTK_RESPONSE_CLOSE:
115 case GTK_RESPONSE_DELETE_EVENT:
116 break;
117 default:
118 NS_WARNING("Unexpected response");
119 break;
122 // A "response" signal won't be sent again but "destroy" will be.
123 g_signal_handlers_disconnect_by_func(chooser, FuncToGpointer(OnDestroy),
124 this);
125 gtk_widget_destroy(chooser);
127 if (mCallback) {
128 mCallback->Done(localHandler);
129 mCallback = nullptr;
131 NS_RELEASE_THIS();