toolkit/system/gnome/nsGIOService.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:f35ca80d5655
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 "nsGIOService.h"
7 #include "nsStringAPI.h"
8 #include "nsIURI.h"
9 #include "nsTArray.h"
10 #include "nsIStringEnumerator.h"
11 #include "nsAutoPtr.h"
12
13 #include <gio/gio.h>
14 #include <gtk/gtk.h>
15 #ifdef MOZ_ENABLE_DBUS
16 #include <dbus/dbus-glib.h>
17 #include <dbus/dbus-glib-lowlevel.h>
18 #endif
19
20
21 char *
22 get_content_type_from_mime_type(const char *mimeType)
23 {
24 GList* contentTypes = g_content_types_get_registered();
25 GList* ct_ptr = contentTypes;
26 char* foundContentType = nullptr;
27
28 while (ct_ptr) {
29 char *mimeTypeFromContentType = g_content_type_get_mime_type((char*)ct_ptr->data);
30 if (strcmp(mimeTypeFromContentType, mimeType) == 0) {
31 foundContentType = g_strdup((char*)ct_ptr->data);
32 g_free(mimeTypeFromContentType);
33 break;
34 }
35 g_free(mimeTypeFromContentType);
36 ct_ptr = ct_ptr->next;
37 }
38 g_list_foreach(contentTypes, (GFunc) g_free, nullptr);
39 g_list_free(contentTypes);
40 return foundContentType;
41 }
42
43 class nsGIOMimeApp MOZ_FINAL : public nsIGIOMimeApp
44 {
45 public:
46 NS_DECL_ISUPPORTS
47 NS_DECL_NSIGIOMIMEAPP
48
49 nsGIOMimeApp(GAppInfo* aApp) : mApp(aApp) {}
50 ~nsGIOMimeApp() { g_object_unref(mApp); }
51
52 private:
53 GAppInfo *mApp;
54 };
55
56 NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp)
57
58 NS_IMETHODIMP
59 nsGIOMimeApp::GetId(nsACString& aId)
60 {
61 aId.Assign(g_app_info_get_id(mApp));
62 return NS_OK;
63 }
64
65 NS_IMETHODIMP
66 nsGIOMimeApp::GetName(nsACString& aName)
67 {
68 aName.Assign(g_app_info_get_name(mApp));
69 return NS_OK;
70 }
71
72 NS_IMETHODIMP
73 nsGIOMimeApp::GetCommand(nsACString& aCommand)
74 {
75 const char *cmd = g_app_info_get_commandline(mApp);
76 if (!cmd)
77 return NS_ERROR_FAILURE;
78 aCommand.Assign(cmd);
79 return NS_OK;
80 }
81
82 NS_IMETHODIMP
83 nsGIOMimeApp::GetExpectsURIs(int32_t* aExpects)
84 {
85 *aExpects = g_app_info_supports_uris(mApp);
86 return NS_OK;
87 }
88
89 NS_IMETHODIMP
90 nsGIOMimeApp::Launch(const nsACString& aUri)
91 {
92 GList uris = { 0 };
93 PromiseFlatCString flatUri(aUri);
94 uris.data = const_cast<char*>(flatUri.get());
95
96 GError *error = nullptr;
97 gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
98
99 if (!result) {
100 g_warning("Cannot launch application: %s", error->message);
101 g_error_free(error);
102 return NS_ERROR_FAILURE;
103 }
104
105 return NS_OK;
106 }
107
108 class GIOUTF8StringEnumerator MOZ_FINAL : public nsIUTF8StringEnumerator
109 {
110 public:
111 GIOUTF8StringEnumerator() : mIndex(0) { }
112 ~GIOUTF8StringEnumerator() { }
113
114 NS_DECL_ISUPPORTS
115 NS_DECL_NSIUTF8STRINGENUMERATOR
116
117 nsTArray<nsCString> mStrings;
118 uint32_t mIndex;
119 };
120
121 NS_IMPL_ISUPPORTS(GIOUTF8StringEnumerator, nsIUTF8StringEnumerator)
122
123 NS_IMETHODIMP
124 GIOUTF8StringEnumerator::HasMore(bool* aResult)
125 {
126 *aResult = mIndex < mStrings.Length();
127 return NS_OK;
128 }
129
130 NS_IMETHODIMP
131 GIOUTF8StringEnumerator::GetNext(nsACString& aResult)
132 {
133 if (mIndex >= mStrings.Length())
134 return NS_ERROR_UNEXPECTED;
135
136 aResult.Assign(mStrings[mIndex]);
137 ++mIndex;
138 return NS_OK;
139 }
140
141 NS_IMETHODIMP
142 nsGIOMimeApp::GetSupportedURISchemes(nsIUTF8StringEnumerator** aSchemes)
143 {
144 *aSchemes = nullptr;
145
146 nsRefPtr<GIOUTF8StringEnumerator> array = new GIOUTF8StringEnumerator();
147 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
148
149 GVfs *gvfs = g_vfs_get_default();
150
151 if (!gvfs) {
152 g_warning("Cannot get GVfs object.");
153 return NS_ERROR_OUT_OF_MEMORY;
154 }
155
156 const gchar* const * uri_schemes = g_vfs_get_supported_uri_schemes(gvfs);
157
158 while (*uri_schemes != nullptr) {
159 if (!array->mStrings.AppendElement(*uri_schemes)) {
160 return NS_ERROR_OUT_OF_MEMORY;
161 }
162 uri_schemes++;
163 }
164
165 NS_ADDREF(*aSchemes = array);
166 return NS_OK;
167 }
168
169 NS_IMETHODIMP
170 nsGIOMimeApp::SetAsDefaultForMimeType(nsACString const& aMimeType)
171 {
172 char *content_type =
173 get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
174 if (!content_type)
175 return NS_ERROR_FAILURE;
176 GError *error = nullptr;
177 g_app_info_set_as_default_for_type(mApp,
178 content_type,
179 &error);
180 if (error) {
181 g_warning("Cannot set application as default for MIME type (%s): %s",
182 PromiseFlatCString(aMimeType).get(),
183 error->message);
184 g_error_free(error);
185 g_free(content_type);
186 return NS_ERROR_FAILURE;
187 }
188
189 g_free(content_type);
190 return NS_OK;
191 }
192 /**
193 * Set default application for files with given extensions
194 * @param fileExts string of space separated extensions
195 * @return NS_OK when application was set as default for given extensions,
196 * NS_ERROR_FAILURE otherwise
197 */
198 NS_IMETHODIMP
199 nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts)
200 {
201 GError *error = nullptr;
202 char *extensions = g_strdup(PromiseFlatCString(fileExts).get());
203 char *ext_pos = extensions;
204 char *space_pos;
205
206 while ( (space_pos = strchr(ext_pos, ' ')) || (*ext_pos != '\0') ) {
207 if (space_pos) {
208 *space_pos = '\0';
209 }
210 g_app_info_set_as_default_for_extension(mApp, ext_pos, &error);
211 if (error) {
212 g_warning("Cannot set application as default for extension (%s): %s",
213 ext_pos,
214 error->message);
215 g_error_free(error);
216 g_free(extensions);
217 return NS_ERROR_FAILURE;
218 }
219 if (space_pos) {
220 ext_pos = space_pos + 1;
221 } else {
222 *ext_pos = '\0';
223 }
224 }
225 g_free(extensions);
226 return NS_OK;
227 }
228
229 /**
230 * Set default application for URI's of a particular scheme
231 * @param aURIScheme string containing the URI scheme
232 * @return NS_OK when application was set as default for URI scheme,
233 * NS_ERROR_FAILURE otherwise
234 */
235 NS_IMETHODIMP
236 nsGIOMimeApp::SetAsDefaultForURIScheme(nsACString const& aURIScheme)
237 {
238 GError *error = nullptr;
239 nsAutoCString contentType("x-scheme-handler/");
240 contentType.Append(aURIScheme);
241
242 g_app_info_set_as_default_for_type(mApp,
243 contentType.get(),
244 &error);
245 if (error) {
246 g_warning("Cannot set application as default for URI scheme (%s): %s",
247 PromiseFlatCString(aURIScheme).get(),
248 error->message);
249 g_error_free(error);
250 return NS_ERROR_FAILURE;
251 }
252
253 return NS_OK;
254 }
255
256 NS_IMPL_ISUPPORTS(nsGIOService, nsIGIOService)
257
258 NS_IMETHODIMP
259 nsGIOService::GetMimeTypeFromExtension(const nsACString& aExtension,
260 nsACString& aMimeType)
261 {
262 nsAutoCString fileExtToUse("file.");
263 fileExtToUse.Append(aExtension);
264
265 gboolean result_uncertain;
266 char *content_type = g_content_type_guess(fileExtToUse.get(),
267 nullptr,
268 0,
269 &result_uncertain);
270 if (!content_type)
271 return NS_ERROR_FAILURE;
272
273 char *mime_type = g_content_type_get_mime_type(content_type);
274 if (!mime_type) {
275 g_free(content_type);
276 return NS_ERROR_FAILURE;
277 }
278
279 aMimeType.Assign(mime_type);
280
281 g_free(mime_type);
282 g_free(content_type);
283
284 return NS_OK;
285 }
286 // used in nsGNOMERegistry
287 // -----------------------------------------------------------------------------
288 NS_IMETHODIMP
289 nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme,
290 nsIGIOMimeApp** aApp)
291 {
292 *aApp = nullptr;
293
294 GAppInfo *app_info = g_app_info_get_default_for_uri_scheme(
295 PromiseFlatCString(aURIScheme).get());
296 if (app_info) {
297 nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
298 NS_ADDREF(*aApp = mozApp);
299 } else {
300 return NS_ERROR_FAILURE;
301 }
302 return NS_OK;
303 }
304
305 NS_IMETHODIMP
306 nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
307 nsIGIOMimeApp** aApp)
308 {
309 *aApp = nullptr;
310 char *content_type =
311 get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
312 if (!content_type)
313 return NS_ERROR_FAILURE;
314
315 GAppInfo *app_info = g_app_info_get_default_for_type(content_type, false);
316 if (app_info) {
317 nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
318 NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
319 NS_ADDREF(*aApp = mozApp);
320 } else {
321 g_free(content_type);
322 return NS_ERROR_FAILURE;
323 }
324 g_free(content_type);
325 return NS_OK;
326 }
327
328 NS_IMETHODIMP
329 nsGIOService::GetDescriptionForMimeType(const nsACString& aMimeType,
330 nsACString& aDescription)
331 {
332 char *content_type =
333 get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
334 if (!content_type)
335 return NS_ERROR_FAILURE;
336
337 char *desc = g_content_type_get_description(content_type);
338 if (!desc) {
339 g_free(content_type);
340 return NS_ERROR_FAILURE;
341 }
342
343 aDescription.Assign(desc);
344 g_free(content_type);
345 g_free(desc);
346 return NS_OK;
347 }
348
349 NS_IMETHODIMP
350 nsGIOService::ShowURI(nsIURI* aURI)
351 {
352 nsAutoCString spec;
353 aURI->GetSpec(spec);
354 GError *error = nullptr;
355 if (!g_app_info_launch_default_for_uri(spec.get(), nullptr, &error)) {
356 g_warning("Could not launch default application for URI: %s", error->message);
357 g_error_free(error);
358 return NS_ERROR_FAILURE;
359 }
360 return NS_OK;
361 }
362
363 NS_IMETHODIMP
364 nsGIOService::ShowURIForInput(const nsACString& aUri)
365 {
366 GFile *file = g_file_new_for_commandline_arg(PromiseFlatCString(aUri).get());
367 char* spec = g_file_get_uri(file);
368 nsresult rv = NS_ERROR_FAILURE;
369 GError *error = nullptr;
370
371 g_app_info_launch_default_for_uri(spec, nullptr, &error);
372 if (error) {
373 g_warning("Cannot launch default application: %s", error->message);
374 g_error_free(error);
375 } else {
376 rv = NS_OK;
377 }
378 g_object_unref(file);
379 g_free(spec);
380
381 return rv;
382 }
383
384 NS_IMETHODIMP
385 nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath)
386 {
387 #ifndef MOZ_ENABLE_DBUS
388 return NS_ERROR_FAILURE;
389 #else
390 GError* error = nullptr;
391 static bool org_freedesktop_FileManager1_exists = true;
392
393 if (!org_freedesktop_FileManager1_exists) {
394 return NS_ERROR_NOT_AVAILABLE;
395 }
396
397 DBusGConnection* dbusGConnection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
398
399 if (!dbusGConnection) {
400 if (error) {
401 g_printerr("Failed to open connection to session bus: %s\n", error->message);
402 g_error_free(error);
403 }
404 return NS_ERROR_FAILURE;
405 }
406
407 char *uri = g_filename_to_uri(PromiseFlatCString(aPath).get(), nullptr, nullptr);
408 if (uri == nullptr) {
409 return NS_ERROR_FAILURE;
410 }
411
412 DBusConnection* dbusConnection = dbus_g_connection_get_connection(dbusGConnection);
413 // Make sure we do not exit the entire program if DBus connection get lost.
414 dbus_connection_set_exit_on_disconnect(dbusConnection, false);
415
416 DBusGProxy* dbusGProxy = dbus_g_proxy_new_for_name(dbusGConnection,
417 "org.freedesktop.FileManager1",
418 "/org/freedesktop/FileManager1",
419 "org.freedesktop.FileManager1");
420
421 const char *uris[2] = { uri, nullptr };
422 gboolean rv_dbus_call = dbus_g_proxy_call (dbusGProxy, "ShowItems", nullptr, G_TYPE_STRV, uris,
423 G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
424
425 g_object_unref(dbusGProxy);
426 dbus_g_connection_unref(dbusGConnection);
427 g_free(uri);
428
429 if (!rv_dbus_call) {
430 org_freedesktop_FileManager1_exists = false;
431 return NS_ERROR_NOT_AVAILABLE;
432 }
433
434 return NS_OK;
435 #endif
436 }
437
438 /**
439 * Create or find already existing application info for specified command
440 * and application name.
441 * @param cmd command to execute
442 * @param appName application name
443 * @param appInfo location where created GAppInfo is stored
444 * @return NS_OK when object is created, NS_ERROR_FAILURE otherwise.
445 */
446 NS_IMETHODIMP
447 nsGIOService::CreateAppFromCommand(nsACString const& cmd,
448 nsACString const& appName,
449 nsIGIOMimeApp** appInfo)
450 {
451 GError *error = nullptr;
452 *appInfo = nullptr;
453
454 GAppInfo *app_info = nullptr, *app_info_from_list = nullptr;
455 GList *apps = g_app_info_get_all();
456 GList *apps_p = apps;
457
458 // Try to find relevant and existing GAppInfo in all installed application
459 // We do this by comparing each GAppInfo's executable with out own
460 while (apps_p) {
461 app_info_from_list = (GAppInfo*) apps_p->data;
462 if (!app_info) {
463 // If the executable is not absolute, get it's full path
464 char *executable = g_find_program_in_path(g_app_info_get_executable(app_info_from_list));
465
466 if (executable && strcmp(executable, PromiseFlatCString(cmd).get()) == 0) {
467 g_object_ref (app_info_from_list);
468 app_info = app_info_from_list;
469 }
470 g_free(executable);
471 }
472
473 g_object_unref(app_info_from_list);
474 apps_p = apps_p->next;
475 }
476 g_list_free(apps);
477
478 if (!app_info) {
479 app_info = g_app_info_create_from_commandline(PromiseFlatCString(cmd).get(),
480 PromiseFlatCString(appName).get(),
481 G_APP_INFO_CREATE_SUPPORTS_URIS,
482 &error);
483 }
484
485 if (!app_info) {
486 g_warning("Cannot create application info from command: %s", error->message);
487 g_error_free(error);
488 return NS_ERROR_FAILURE;
489 }
490 nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
491 NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
492 NS_ADDREF(*appInfo = mozApp);
493 return NS_OK;
494 }

mercurial