Line data Source code
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/. */
5 :
6 : #include "mozilla/Types.h"
7 :
8 : #include <gtk/gtk.h>
9 :
10 : #include "nsApplicationChooser.h"
11 : #include "WidgetUtils.h"
12 : #include "nsIMIMEInfo.h"
13 : #include "nsIWidget.h"
14 : #include "nsCExternalHandlerService.h"
15 : #include "nsComponentManagerUtils.h"
16 : #include "nsGtkUtils.h"
17 : #include "nsPIDOMWindow.h"
18 :
19 : using namespace mozilla;
20 :
21 0 : NS_IMPL_ISUPPORTS(nsApplicationChooser, nsIApplicationChooser)
22 :
23 0 : nsApplicationChooser::nsApplicationChooser()
24 : {
25 0 : }
26 :
27 0 : nsApplicationChooser::~nsApplicationChooser()
28 : {
29 0 : }
30 :
31 : NS_IMETHODIMP
32 0 : nsApplicationChooser::Init(mozIDOMWindowProxy* aParent,
33 : const nsACString& aTitle)
34 : {
35 0 : NS_ENSURE_TRUE(aParent, NS_ERROR_FAILURE);
36 0 : auto* parent = nsPIDOMWindowOuter::From(aParent);
37 0 : mParentWidget = widget::WidgetUtils::DOMWindowToWidget(parent);
38 0 : mWindowTitle.Assign(aTitle);
39 0 : return NS_OK;
40 : }
41 :
42 : NS_IMETHODIMP
43 0 : nsApplicationChooser::Open(const nsACString& aContentType, nsIApplicationChooserFinishedCallback *aCallback)
44 : {
45 0 : MOZ_ASSERT(aCallback);
46 0 : if (mCallback) {
47 0 : NS_WARNING("Chooser is already in progress.");
48 0 : return NS_ERROR_ALREADY_INITIALIZED;
49 : }
50 0 : mCallback = aCallback;
51 0 : NS_ENSURE_TRUE(mParentWidget, NS_ERROR_FAILURE);
52 : GtkWindow *parent_widget =
53 0 : GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
54 :
55 : GtkWidget* chooser =
56 0 : gtk_app_chooser_dialog_new_for_content_type(parent_widget,
57 : (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
58 0 : PromiseFlatCString(aContentType).get());
59 0 : gtk_app_chooser_dialog_set_heading(GTK_APP_CHOOSER_DIALOG(chooser), mWindowTitle.BeginReading());
60 0 : NS_ADDREF_THIS();
61 0 : g_signal_connect(chooser, "response", G_CALLBACK(OnResponse), this);
62 0 : g_signal_connect(chooser, "destroy", G_CALLBACK(OnDestroy), this);
63 0 : gtk_widget_show(chooser);
64 0 : return NS_OK;
65 : }
66 :
67 : /* static */ void
68 0 : nsApplicationChooser::OnResponse(GtkWidget* chooser, gint response_id, gpointer user_data)
69 : {
70 0 : static_cast<nsApplicationChooser*>(user_data)->Done(chooser, response_id);
71 0 : }
72 :
73 : /* static */ void
74 0 : nsApplicationChooser::OnDestroy(GtkWidget *chooser, gpointer user_data)
75 : {
76 0 : static_cast<nsApplicationChooser*>(user_data)->Done(chooser, GTK_RESPONSE_CANCEL);
77 0 : }
78 :
79 0 : void nsApplicationChooser::Done(GtkWidget* chooser, gint response)
80 : {
81 0 : nsCOMPtr<nsILocalHandlerApp> localHandler;
82 : nsresult rv;
83 0 : switch (response) {
84 : case GTK_RESPONSE_OK:
85 : case GTK_RESPONSE_ACCEPT:
86 : {
87 0 : localHandler = do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
88 0 : if (NS_FAILED(rv)) {
89 0 : NS_WARNING("Out of memory.");
90 0 : break;
91 : }
92 0 : GAppInfo *app_info = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(chooser));
93 :
94 0 : nsCOMPtr<nsIFile> localExecutable;
95 0 : gchar *fileWithFullPath = g_find_program_in_path(g_app_info_get_executable(app_info));
96 0 : rv = NS_NewNativeLocalFile(nsDependentCString(fileWithFullPath), false, getter_AddRefs(localExecutable));
97 0 : g_free(fileWithFullPath);
98 0 : if (NS_FAILED(rv)) {
99 0 : NS_WARNING("Cannot create local filename.");
100 0 : localHandler = nullptr;
101 : } else {
102 0 : localHandler->SetExecutable(localExecutable);
103 0 : localHandler->SetName(NS_ConvertUTF8toUTF16(g_app_info_get_display_name(app_info)));
104 : }
105 0 : g_object_unref(app_info);
106 : }
107 :
108 0 : break;
109 : case GTK_RESPONSE_CANCEL:
110 : case GTK_RESPONSE_CLOSE:
111 : case GTK_RESPONSE_DELETE_EVENT:
112 0 : break;
113 : default:
114 0 : NS_WARNING("Unexpected response");
115 0 : break;
116 : }
117 :
118 : // A "response" signal won't be sent again but "destroy" will be.
119 0 : g_signal_handlers_disconnect_by_func(chooser, FuncToGpointer(OnDestroy), this);
120 0 : gtk_widget_destroy(chooser);
121 :
122 0 : if (mCallback) {
123 0 : mCallback->Done(localHandler);
124 0 : mCallback = nullptr;
125 : }
126 0 : NS_RELEASE_THIS();
127 0 : }
128 :
|