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"
10 #include "nsApplicationChooser.h"
11 #include "WidgetUtils.h"
12 #include "nsIMIMEInfo.h"
13 #include "nsIWidget.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;
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
);
39 nsApplicationChooser::Open(const nsACString
& aContentType
,
40 nsIApplicationChooserFinishedCallback
* aCallback
) {
41 MOZ_ASSERT(aCallback
);
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(
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());
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
);
65 void nsApplicationChooser::OnResponse(GtkWidget
* chooser
, gint response_id
,
67 static_cast<nsApplicationChooser
*>(user_data
)->Done(chooser
, response_id
);
71 void nsApplicationChooser::OnDestroy(GtkWidget
* chooser
, gpointer user_data
) {
72 static_cast<nsApplicationChooser
*>(user_data
)->Done(chooser
,
76 void nsApplicationChooser::Done(GtkWidget
* chooser
, gint response
) {
77 nsCOMPtr
<nsILocalHandlerApp
> localHandler
;
81 case GTK_RESPONSE_ACCEPT
: {
82 localHandler
= do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID
, &rv
);
84 NS_WARNING("Out of memory.");
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.");
98 rv
= NS_NewNativeLocalFile(nsDependentCString(fileWithFullPath
), false,
99 getter_AddRefs(localExecutable
));
100 g_free(fileWithFullPath
);
102 NS_WARNING("Cannot create local filename.");
103 localHandler
= nullptr;
105 localHandler
->SetExecutable(localExecutable
);
106 localHandler
->SetName(
107 NS_ConvertUTF8toUTF16(g_app_info_get_display_name(app_info
)));
109 g_object_unref(app_info
);
113 case GTK_RESPONSE_CANCEL
:
114 case GTK_RESPONSE_CLOSE
:
115 case GTK_RESPONSE_DELETE_EVENT
:
118 NS_WARNING("Unexpected response");
122 // A "response" signal won't be sent again but "destroy" will be.
123 g_signal_handlers_disconnect_by_func(chooser
, FuncToGpointer(OnDestroy
),
125 gtk_widget_destroy(chooser
);
128 mCallback
->Done(localHandler
);