summaryrefslogtreecommitdiffstats
path: root/toolkit/system/gnome
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /toolkit/system/gnome
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/system/gnome')
-rw-r--r--toolkit/system/gnome/moz.build37
-rw-r--r--toolkit/system/gnome/nsAlertsIconListener.cpp327
-rw-r--r--toolkit/system/gnome/nsAlertsIconListener.h91
-rw-r--r--toolkit/system/gnome/nsGConfService.cpp305
-rw-r--r--toolkit/system/gnome/nsGConfService.h31
-rw-r--r--toolkit/system/gnome/nsGIOService.cpp475
-rw-r--r--toolkit/system/gnome/nsGIOService.h24
-rw-r--r--toolkit/system/gnome/nsGSettingsService.cpp350
-rw-r--r--toolkit/system/gnome/nsGSettingsService.h27
-rw-r--r--toolkit/system/gnome/nsGnomeModule.cpp78
-rw-r--r--toolkit/system/gnome/nsPackageKitService.cpp267
-rw-r--r--toolkit/system/gnome/nsPackageKitService.h26
-rw-r--r--toolkit/system/gnome/nsSystemAlertsService.cpp118
-rw-r--r--toolkit/system/gnome/nsSystemAlertsService.h39
14 files changed, 2195 insertions, 0 deletions
diff --git a/toolkit/system/gnome/moz.build b/toolkit/system/gnome/moz.build
new file mode 100644
index 000000000..14b472be3
--- /dev/null
+++ b/toolkit/system/gnome/moz.build
@@ -0,0 +1,37 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+ 'nsAlertsIconListener.cpp',
+ 'nsGnomeModule.cpp',
+ 'nsSystemAlertsService.cpp',
+]
+
+if CONFIG['MOZ_ENABLE_GCONF']:
+ SOURCES += [
+ 'nsGConfService.cpp',
+ ]
+
+if CONFIG['MOZ_ENABLE_GIO']:
+ SOURCES += [
+ 'nsGIOService.cpp',
+ 'nsGSettingsService.cpp',
+ 'nsPackageKitService.cpp'
+ ]
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '/toolkit/components/build/',
+]
+
+CXXFLAGS += CONFIG['MOZ_GCONF_CFLAGS']
+CXXFLAGS += CONFIG['MOZ_GIO_CFLAGS']
+CXXFLAGS += CONFIG['GLIB_CFLAGS']
+CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
+
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
+ CXXFLAGS += CONFIG['TK_CFLAGS']
diff --git a/toolkit/system/gnome/nsAlertsIconListener.cpp b/toolkit/system/gnome/nsAlertsIconListener.cpp
new file mode 100644
index 000000000..b11672d30
--- /dev/null
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -0,0 +1,327 @@
+/* -*- 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 "nsAlertsIconListener.h"
+#include "imgIContainer.h"
+#include "imgIRequest.h"
+#include "nsNetUtil.h"
+#include "nsServiceManagerUtils.h"
+#include "nsSystemAlertsService.h"
+#include "nsIAlertsService.h"
+#include "nsICancelable.h"
+#include "nsIImageToPixbuf.h"
+#include "nsIStringBundle.h"
+#include "nsIObserverService.h"
+#include "nsIURI.h"
+#include "nsCRT.h"
+
+#include <dlfcn.h>
+#include <gdk/gdk.h>
+
+static bool gHasActions = false;
+static bool gHasCaps = false;
+
+void* nsAlertsIconListener::libNotifyHandle = nullptr;
+bool nsAlertsIconListener::libNotifyNotAvail = false;
+nsAlertsIconListener::notify_is_initted_t nsAlertsIconListener::notify_is_initted = nullptr;
+nsAlertsIconListener::notify_init_t nsAlertsIconListener::notify_init = nullptr;
+nsAlertsIconListener::notify_get_server_caps_t nsAlertsIconListener::notify_get_server_caps = nullptr;
+nsAlertsIconListener::notify_notification_new_t nsAlertsIconListener::notify_notification_new = nullptr;
+nsAlertsIconListener::notify_notification_show_t nsAlertsIconListener::notify_notification_show = nullptr;
+nsAlertsIconListener::notify_notification_set_icon_from_pixbuf_t nsAlertsIconListener::notify_notification_set_icon_from_pixbuf = nullptr;
+nsAlertsIconListener::notify_notification_add_action_t nsAlertsIconListener::notify_notification_add_action = nullptr;
+nsAlertsIconListener::notify_notification_close_t nsAlertsIconListener::notify_notification_close = nullptr;
+
+static void notify_action_cb(NotifyNotification *notification,
+ gchar *action, gpointer user_data)
+{
+ nsAlertsIconListener* alert = static_cast<nsAlertsIconListener*> (user_data);
+ alert->SendCallback();
+}
+
+static void notify_closed_marshal(GClosure* closure,
+ GValue* return_value,
+ guint n_param_values,
+ const GValue* param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ MOZ_ASSERT(n_param_values >= 1, "No object in params");
+
+ nsAlertsIconListener* alert =
+ static_cast<nsAlertsIconListener*>(closure->data);
+ alert->SendClosed();
+ NS_RELEASE(alert);
+}
+
+static GdkPixbuf*
+GetPixbufFromImgRequest(imgIRequest* aRequest)
+{
+ nsCOMPtr<imgIContainer> image;
+ nsresult rv = aRequest->GetImage(getter_AddRefs(image));
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
+ do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
+
+ return imgToPixbuf->ConvertImageToPixbuf(image);
+}
+
+NS_IMPL_ISUPPORTS(nsAlertsIconListener, nsIAlertNotificationImageListener,
+ nsIObserver, nsISupportsWeakReference)
+
+nsAlertsIconListener::nsAlertsIconListener(nsSystemAlertsService* aBackend,
+ const nsAString& aAlertName)
+: mAlertName(aAlertName),
+ mBackend(aBackend),
+ mNotification(nullptr)
+{
+ if (!libNotifyHandle && !libNotifyNotAvail) {
+ libNotifyHandle = dlopen("libnotify.so.4", RTLD_LAZY);
+ if (!libNotifyHandle) {
+ libNotifyHandle = dlopen("libnotify.so.1", RTLD_LAZY);
+ if (!libNotifyHandle) {
+ libNotifyNotAvail = true;
+ return;
+ }
+ }
+
+ notify_is_initted = (notify_is_initted_t)dlsym(libNotifyHandle, "notify_is_initted");
+ notify_init = (notify_init_t)dlsym(libNotifyHandle, "notify_init");
+ notify_get_server_caps = (notify_get_server_caps_t)dlsym(libNotifyHandle, "notify_get_server_caps");
+ notify_notification_new = (notify_notification_new_t)dlsym(libNotifyHandle, "notify_notification_new");
+ notify_notification_show = (notify_notification_show_t)dlsym(libNotifyHandle, "notify_notification_show");
+ notify_notification_set_icon_from_pixbuf = (notify_notification_set_icon_from_pixbuf_t)dlsym(libNotifyHandle, "notify_notification_set_icon_from_pixbuf");
+ notify_notification_add_action = (notify_notification_add_action_t)dlsym(libNotifyHandle, "notify_notification_add_action");
+ notify_notification_close = (notify_notification_close_t)dlsym(libNotifyHandle, "notify_notification_close");
+ if (!notify_is_initted || !notify_init || !notify_get_server_caps || !notify_notification_new || !notify_notification_show || !notify_notification_set_icon_from_pixbuf || !notify_notification_add_action || !notify_notification_close) {
+ dlclose(libNotifyHandle);
+ libNotifyHandle = nullptr;
+ }
+ }
+}
+
+nsAlertsIconListener::~nsAlertsIconListener()
+{
+ mBackend->RemoveListener(mAlertName, this);
+ // Don't dlclose libnotify as it uses atexit().
+}
+
+NS_IMETHODIMP
+nsAlertsIconListener::OnImageMissing(nsISupports*)
+{
+ // This notification doesn't have an image, or there was an error getting
+ // the image. Show the notification without an icon.
+ return ShowAlert(nullptr);
+}
+
+NS_IMETHODIMP
+nsAlertsIconListener::OnImageReady(nsISupports*, imgIRequest* aRequest)
+{
+ GdkPixbuf* imagePixbuf = GetPixbufFromImgRequest(aRequest);
+ if (!imagePixbuf) {
+ ShowAlert(nullptr);
+ } else {
+ ShowAlert(imagePixbuf);
+ g_object_unref(imagePixbuf);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
+{
+ if (!mBackend->IsActiveListener(mAlertName, this))
+ return NS_OK;
+
+ mNotification = notify_notification_new(mAlertTitle.get(), mAlertText.get(),
+ nullptr, nullptr);
+
+ if (!mNotification)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsCOMPtr<nsIObserverService> obsServ =
+ do_GetService("@mozilla.org/observer-service;1");
+ if (obsServ)
+ obsServ->AddObserver(this, "quit-application", true);
+
+ if (aPixbuf)
+ notify_notification_set_icon_from_pixbuf(mNotification, aPixbuf);
+
+ NS_ADDREF(this);
+ if (mAlertHasAction) {
+ // What we put as the label doesn't matter here, if the action
+ // string is "default" then that makes the entire bubble clickable
+ // rather than creating a button.
+ notify_notification_add_action(mNotification, "default", "Activate",
+ notify_action_cb, this, nullptr);
+ }
+
+ // Fedora 10 calls NotifyNotification "closed" signal handlers with a
+ // different signature, so a marshaller is used instead of a C callback to
+ // get the user_data (this) in a parseable format. |closure| is created
+ // with a floating reference, which gets sunk by g_signal_connect_closure().
+ GClosure* closure = g_closure_new_simple(sizeof(GClosure), this);
+ g_closure_set_marshal(closure, notify_closed_marshal);
+ mClosureHandler = g_signal_connect_closure(mNotification, "closed", closure, FALSE);
+ GError* error = nullptr;
+ if (!notify_notification_show(mNotification, &error)) {
+ NS_WARNING(error->message);
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (mAlertListener)
+ mAlertListener->Observe(nullptr, "alertshow", mAlertCookie.get());
+
+ return NS_OK;
+}
+
+void
+nsAlertsIconListener::SendCallback()
+{
+ if (mAlertListener)
+ mAlertListener->Observe(nullptr, "alertclickcallback", mAlertCookie.get());
+}
+
+void
+nsAlertsIconListener::SendClosed()
+{
+ if (mNotification) {
+ g_object_unref(mNotification);
+ mNotification = nullptr;
+ }
+ NotifyFinished();
+}
+
+NS_IMETHODIMP
+nsAlertsIconListener::Observe(nsISupports *aSubject, const char *aTopic,
+ const char16_t *aData) {
+ // We need to close any open notifications upon application exit, otherwise
+ // we will leak since libnotify holds a ref for us.
+ if (!nsCRT::strcmp(aTopic, "quit-application") && mNotification) {
+ g_signal_handler_disconnect(mNotification, mClosureHandler);
+ g_object_unref(mNotification);
+ mNotification = nullptr;
+ Release(); // equivalent to NS_RELEASE(this)
+ }
+ return NS_OK;
+}
+
+nsresult
+nsAlertsIconListener::Close()
+{
+ if (mIconRequest) {
+ mIconRequest->Cancel(NS_BINDING_ABORTED);
+ mIconRequest = nullptr;
+ }
+
+ if (!mNotification) {
+ NotifyFinished();
+ return NS_OK;
+ }
+
+ GError* error = nullptr;
+ if (!notify_notification_close(mNotification, &error)) {
+ NS_WARNING(error->message);
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsAlertsIconListener::InitAlertAsync(nsIAlertNotification* aAlert,
+ nsIObserver* aAlertListener)
+{
+ if (!libNotifyHandle)
+ return NS_ERROR_FAILURE;
+
+ if (!notify_is_initted()) {
+ // Give the name of this application to libnotify
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ do_GetService(NS_STRINGBUNDLE_CONTRACTID);
+
+ nsAutoCString appShortName;
+ if (bundleService) {
+ nsCOMPtr<nsIStringBundle> bundle;
+ bundleService->CreateBundle("chrome://branding/locale/brand.properties",
+ getter_AddRefs(bundle));
+ nsAutoString appName;
+
+ if (bundle) {
+ bundle->GetStringFromName(u"brandShortName",
+ getter_Copies(appName));
+ appShortName = NS_ConvertUTF16toUTF8(appName);
+ } else {
+ NS_WARNING("brand.properties not present, using default application name");
+ appShortName.AssignLiteral("Mozilla");
+ }
+ } else {
+ appShortName.AssignLiteral("Mozilla");
+ }
+
+ if (!notify_init(appShortName.get()))
+ return NS_ERROR_FAILURE;
+
+ GList *server_caps = notify_get_server_caps();
+ if (server_caps) {
+ gHasCaps = true;
+ for (GList* cap = server_caps; cap != nullptr; cap = cap->next) {
+ if (!strcmp((char*) cap->data, "actions")) {
+ gHasActions = true;
+ break;
+ }
+ }
+ g_list_foreach(server_caps, (GFunc)g_free, nullptr);
+ g_list_free(server_caps);
+ }
+ }
+
+ if (!gHasCaps) {
+ // if notify_get_server_caps() failed above we need to assume
+ // there is no notification-server to display anything
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv = aAlert->GetTextClickable(&mAlertHasAction);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!gHasActions && mAlertHasAction)
+ return NS_ERROR_FAILURE; // No good, fallback to XUL
+
+ nsAutoString title;
+ rv = aAlert->GetTitle(title);
+ NS_ENSURE_SUCCESS(rv, rv);
+ // Workaround for a libnotify bug - blank titles aren't dealt with
+ // properly so we use a space
+ if (title.IsEmpty()) {
+ mAlertTitle = NS_LITERAL_CSTRING(" ");
+ } else {
+ mAlertTitle = NS_ConvertUTF16toUTF8(title);
+ }
+
+ nsAutoString text;
+ rv = aAlert->GetText(text);
+ NS_ENSURE_SUCCESS(rv, rv);
+ mAlertText = NS_ConvertUTF16toUTF8(text);
+
+ mAlertListener = aAlertListener;
+
+ rv = aAlert->GetCookie(mAlertCookie);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return aAlert->LoadImage(/* aTimeout = */ 0, this, /* aUserData = */ nullptr,
+ getter_AddRefs(mIconRequest));
+}
+
+void nsAlertsIconListener::NotifyFinished()
+{
+ if (mAlertListener)
+ mAlertListener->Observe(nullptr, "alertfinished", mAlertCookie.get());
+}
diff --git a/toolkit/system/gnome/nsAlertsIconListener.h b/toolkit/system/gnome/nsAlertsIconListener.h
new file mode 100644
index 000000000..f3a745d33
--- /dev/null
+++ b/toolkit/system/gnome/nsAlertsIconListener.h
@@ -0,0 +1,91 @@
+/* -*- 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 nsAlertsIconListener_h__
+#define nsAlertsIconListener_h__
+
+#include "nsCOMPtr.h"
+#include "nsIAlertsService.h"
+#include "nsString.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+class nsIAlertNotification;
+class nsICancelable;
+class nsSystemAlertsService;
+
+struct NotifyNotification;
+
+class nsAlertsIconListener : public nsIAlertNotificationImageListener,
+ public nsIObserver,
+ public nsSupportsWeakReference
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIALERTNOTIFICATIONIMAGELISTENER
+ NS_DECL_NSIOBSERVER
+
+ nsAlertsIconListener(nsSystemAlertsService* aBackend,
+ const nsAString& aAlertName);
+
+ nsresult InitAlertAsync(nsIAlertNotification* aAlert,
+ nsIObserver* aAlertListener);
+ nsresult Close();
+
+ void SendCallback();
+ void SendClosed();
+
+protected:
+ virtual ~nsAlertsIconListener();
+
+ /**
+ * The only difference between libnotify.so.4 and libnotify.so.1 for these symbols
+ * is that notify_notification_new takes three arguments in libnotify.so.4 and
+ * four in libnotify.so.1.
+ * Passing the fourth argument as NULL is binary compatible.
+ */
+ typedef void (*NotifyActionCallback)(NotifyNotification*, char*, gpointer);
+ typedef bool (*notify_is_initted_t)(void);
+ typedef bool (*notify_init_t)(const char*);
+ typedef GList* (*notify_get_server_caps_t)(void);
+ typedef NotifyNotification* (*notify_notification_new_t)(const char*, const char*, const char*, const char*);
+ typedef bool (*notify_notification_show_t)(void*, GError**);
+ typedef void (*notify_notification_set_icon_from_pixbuf_t)(void*, GdkPixbuf*);
+ typedef void (*notify_notification_add_action_t)(void*, const char*, const char*, NotifyActionCallback, gpointer, GFreeFunc);
+ typedef bool (*notify_notification_close_t)(void*, GError**);
+
+ nsCOMPtr<nsICancelable> mIconRequest;
+ nsCString mAlertTitle;
+ nsCString mAlertText;
+
+ nsCOMPtr<nsIObserver> mAlertListener;
+ nsString mAlertCookie;
+ nsString mAlertName;
+
+ RefPtr<nsSystemAlertsService> mBackend;
+
+ bool mAlertHasAction;
+
+ static void* libNotifyHandle;
+ static bool libNotifyNotAvail;
+ static notify_is_initted_t notify_is_initted;
+ static notify_init_t notify_init;
+ static notify_get_server_caps_t notify_get_server_caps;
+ static notify_notification_new_t notify_notification_new;
+ static notify_notification_show_t notify_notification_show;
+ static notify_notification_set_icon_from_pixbuf_t notify_notification_set_icon_from_pixbuf;
+ static notify_notification_add_action_t notify_notification_add_action;
+ static notify_notification_close_t notify_notification_close;
+ NotifyNotification* mNotification;
+ gulong mClosureHandler;
+
+ nsresult ShowAlert(GdkPixbuf* aPixbuf);
+
+ void NotifyFinished();
+};
+
+#endif
diff --git a/toolkit/system/gnome/nsGConfService.cpp b/toolkit/system/gnome/nsGConfService.cpp
new file mode 100644
index 000000000..ede71e588
--- /dev/null
+++ b/toolkit/system/gnome/nsGConfService.cpp
@@ -0,0 +1,305 @@
+/* -*- 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/ArrayUtils.h"
+#include "nsGConfService.h"
+#include "nsString.h"
+#include "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIMutableArray.h"
+#include "prlink.h"
+
+#include <gconf/gconf-client.h>
+
+using namespace mozilla;
+
+#define GCONF_FUNCTIONS \
+ FUNC(gconf_client_get_default, GConfClient*, (void)) \
+ FUNC(gconf_client_get_bool, gboolean, (GConfClient*, const gchar*, GError**)) \
+ FUNC(gconf_client_get_string, gchar*, (GConfClient*, const gchar*, GError**)) \
+ FUNC(gconf_client_get_int, gint, (GConfClient*, const gchar*, GError**)) \
+ FUNC(gconf_client_get_float, gdouble, (GConfClient*, const gchar*, GError**)) \
+ FUNC(gconf_client_get_list, GSList*, (GConfClient*, const gchar*, GConfValueType, GError**)) \
+ FUNC(gconf_client_set_bool, gboolean, (GConfClient*, const gchar*, gboolean, GError**)) \
+ FUNC(gconf_client_set_string, gboolean, (GConfClient*, const gchar*, const gchar*, GError**)) \
+ FUNC(gconf_client_set_int, gboolean, (GConfClient*, const gchar*, gint, GError**)) \
+ FUNC(gconf_client_set_float, gboolean, (GConfClient*, const gchar*, gdouble, GError**)) \
+ FUNC(gconf_client_unset, gboolean, (GConfClient*, const gchar*, GError**))
+
+#define FUNC(name, type, params) \
+ typedef type (*_##name##_fn) params; \
+ static _##name##_fn _##name;
+
+GCONF_FUNCTIONS
+
+#undef FUNC
+
+#define gconf_client_get_default _gconf_client_get_default
+#define gconf_client_get_bool _gconf_client_get_bool
+#define gconf_client_get_string _gconf_client_get_string
+#define gconf_client_get_int _gconf_client_get_int
+#define gconf_client_get_float _gconf_client_get_float
+#define gconf_client_get_list _gconf_client_get_list
+#define gconf_client_set_bool _gconf_client_set_bool
+#define gconf_client_set_string _gconf_client_set_string
+#define gconf_client_set_int _gconf_client_set_int
+#define gconf_client_set_float _gconf_client_set_float
+#define gconf_client_unset _gconf_client_unset
+
+static PRLibrary *gconfLib = nullptr;
+
+typedef void (*nsGConfFunc)();
+struct nsGConfDynamicFunction {
+ const char *functionName;
+ nsGConfFunc *function;
+};
+
+nsGConfService::~nsGConfService()
+{
+ if (mClient)
+ g_object_unref(mClient);
+
+ // We don't unload gconf here because liborbit uses atexit(). In addition to
+ // this, it's not a good idea to unload any gobject based library, as it
+ // leaves types registered in glib's type system
+}
+
+nsresult
+nsGConfService::Init()
+{
+#define FUNC(name, type, params) { #name, (nsGConfFunc *)&_##name },
+ static const nsGConfDynamicFunction kGConfSymbols[] = {
+ GCONF_FUNCTIONS
+ };
+#undef FUNC
+
+ if (!gconfLib) {
+ gconfLib = PR_LoadLibrary("libgconf-2.so.4");
+ if (!gconfLib)
+ return NS_ERROR_FAILURE;
+ }
+
+ for (uint32_t i = 0; i < ArrayLength(kGConfSymbols); i++) {
+ *kGConfSymbols[i].function =
+ PR_FindFunctionSymbol(gconfLib, kGConfSymbols[i].functionName);
+ if (!*kGConfSymbols[i].function) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ mClient = gconf_client_get_default();
+ return mClient ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMPL_ISUPPORTS(nsGConfService, nsIGConfService)
+
+NS_IMETHODIMP
+nsGConfService::GetBool(const nsACString &aKey, bool *aResult)
+{
+ GError* error = nullptr;
+ *aResult = gconf_client_get_bool(mClient, PromiseFlatCString(aKey).get(),
+ &error);
+
+ if (error) {
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::GetString(const nsACString &aKey, nsACString &aResult)
+{
+ GError* error = nullptr;
+ gchar *result = gconf_client_get_string(mClient,
+ PromiseFlatCString(aKey).get(),
+ &error);
+
+ if (error) {
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ // We do a string copy here so that the caller doesn't need to worry about
+ // freeing the string with g_free().
+
+ aResult.Assign(result);
+ g_free(result);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::GetInt(const nsACString &aKey, int32_t* aResult)
+{
+ GError* error = nullptr;
+ *aResult = gconf_client_get_int(mClient, PromiseFlatCString(aKey).get(),
+ &error);
+
+ if (error) {
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::GetFloat(const nsACString &aKey, float* aResult)
+{
+ GError* error = nullptr;
+ *aResult = gconf_client_get_float(mClient, PromiseFlatCString(aKey).get(),
+ &error);
+
+ if (error) {
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::GetStringList(const nsACString &aKey, nsIArray** aResult)
+{
+ nsCOMPtr<nsIMutableArray> items(do_CreateInstance(NS_ARRAY_CONTRACTID));
+ if (!items)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ GError* error = nullptr;
+ GSList* list = gconf_client_get_list(mClient, PromiseFlatCString(aKey).get(),
+ GCONF_VALUE_STRING, &error);
+ if (error) {
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ for (GSList* l = list; l; l = l->next) {
+ nsCOMPtr<nsISupportsString> obj(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
+ if (!obj) {
+ g_slist_free(list);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ obj->SetData(NS_ConvertUTF8toUTF16((const char*)l->data));
+ items->AppendElement(obj, false);
+ g_free(l->data);
+ }
+
+ g_slist_free(list);
+ items.forget(aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::SetBool(const nsACString &aKey, bool aValue)
+{
+ bool res = gconf_client_set_bool(mClient, PromiseFlatCString(aKey).get(),
+ aValue, nullptr);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGConfService::SetString(const nsACString &aKey, const nsACString &aValue)
+{
+ bool res = gconf_client_set_string(mClient, PromiseFlatCString(aKey).get(),
+ PromiseFlatCString(aValue).get(),
+ nullptr);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGConfService::SetInt(const nsACString &aKey, int32_t aValue)
+{
+ bool res = gconf_client_set_int(mClient, PromiseFlatCString(aKey).get(),
+ aValue, nullptr);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGConfService::SetFloat(const nsACString &aKey, float aValue)
+{
+ bool res = gconf_client_set_float(mClient, PromiseFlatCString(aKey).get(),
+ aValue, nullptr);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGConfService::GetAppForProtocol(const nsACString &aScheme, bool *aEnabled,
+ nsACString &aHandler)
+{
+ nsAutoCString key("/desktop/gnome/url-handlers/");
+ key.Append(aScheme);
+ key.AppendLiteral("/command");
+
+ GError *err = nullptr;
+ gchar *command = gconf_client_get_string(mClient, key.get(), &err);
+ if (!err && command) {
+ key.Replace(key.Length() - 7, 7, NS_LITERAL_CSTRING("enabled"));
+ *aEnabled = gconf_client_get_bool(mClient, key.get(), &err);
+ } else {
+ *aEnabled = false;
+ }
+
+ aHandler.Assign(command);
+ g_free(command);
+
+ if (err) {
+ g_error_free(err);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::HandlerRequiresTerminal(const nsACString &aScheme,
+ bool *aResult)
+{
+ nsAutoCString key("/desktop/gnome/url-handlers/");
+ key.Append(aScheme);
+ key.AppendLiteral("/requires_terminal");
+
+ GError *err = nullptr;
+ *aResult = gconf_client_get_bool(mClient, key.get(), &err);
+ if (err) {
+ g_error_free(err);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::SetAppForProtocol(const nsACString &aScheme,
+ const nsACString &aCommand)
+{
+ nsAutoCString key("/desktop/gnome/url-handlers/");
+ key.Append(aScheme);
+ key.AppendLiteral("/command");
+
+ bool res = gconf_client_set_string(mClient, key.get(),
+ PromiseFlatCString(aCommand).get(),
+ nullptr);
+ if (res) {
+ key.Replace(key.Length() - 7, 7, NS_LITERAL_CSTRING("enabled"));
+ res = gconf_client_set_bool(mClient, key.get(), true, nullptr);
+ if (res) {
+ key.Replace(key.Length() - 7, 7, NS_LITERAL_CSTRING("needs_terminal"));
+ res = gconf_client_set_bool(mClient, key.get(), false, nullptr);
+ if (res) {
+ key.Replace(key.Length() - 14, 14, NS_LITERAL_CSTRING("command-id"));
+ res = gconf_client_unset(mClient, key.get(), nullptr);
+ }
+ }
+ }
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
diff --git a/toolkit/system/gnome/nsGConfService.h b/toolkit/system/gnome/nsGConfService.h
new file mode 100644
index 000000000..4e500a40d
--- /dev/null
+++ b/toolkit/system/gnome/nsGConfService.h
@@ -0,0 +1,31 @@
+/* -*- 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 nsGConfService_h_
+#define nsGConfService_h_
+
+#include "nsIGConfService.h"
+#include "gconf/gconf-client.h"
+#include "mozilla/Attributes.h"
+
+#define NS_GCONFSERVICE_CID \
+{0xd96d5985, 0xa13a, 0x4bdc, {0x93, 0x86, 0xef, 0x34, 0x8d, 0x7a, 0x97, 0xa1}}
+
+class nsGConfService final : public nsIGConfService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGCONFSERVICE
+
+ nsGConfService() : mClient(nullptr) {}
+ nsresult Init();
+
+private:
+ ~nsGConfService();
+
+ GConfClient *mClient;
+};
+
+#endif
diff --git a/toolkit/system/gnome/nsGIOService.cpp b/toolkit/system/gnome/nsGIOService.cpp
new file mode 100644
index 000000000..9196c7d76
--- /dev/null
+++ b/toolkit/system/gnome/nsGIOService.cpp
@@ -0,0 +1,475 @@
+/* -*- 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 "nsGIOService.h"
+#include "nsString.h"
+#include "nsIURI.h"
+#include "nsTArray.h"
+#include "nsIStringEnumerator.h"
+#include "nsAutoPtr.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#ifdef MOZ_ENABLE_DBUS
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#endif
+
+
+class nsGIOMimeApp final : public nsIGIOMimeApp
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGIOMIMEAPP
+
+ explicit nsGIOMimeApp(GAppInfo* aApp) : mApp(aApp) {}
+
+private:
+ ~nsGIOMimeApp() { g_object_unref(mApp); }
+
+ GAppInfo *mApp;
+};
+
+NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp)
+
+NS_IMETHODIMP
+nsGIOMimeApp::GetId(nsACString& aId)
+{
+ aId.Assign(g_app_info_get_id(mApp));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::GetName(nsACString& aName)
+{
+ aName.Assign(g_app_info_get_name(mApp));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::GetCommand(nsACString& aCommand)
+{
+ const char *cmd = g_app_info_get_commandline(mApp);
+ if (!cmd)
+ return NS_ERROR_FAILURE;
+ aCommand.Assign(cmd);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::GetExpectsURIs(int32_t* aExpects)
+{
+ *aExpects = g_app_info_supports_uris(mApp);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::Launch(const nsACString& aUri)
+{
+ GList uris = { 0 };
+ nsPromiseFlatCString flatUri(aUri);
+ uris.data = const_cast<char*>(flatUri.get());
+
+ GError *error = nullptr;
+ gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
+
+ if (!result) {
+ g_warning("Cannot launch application: %s", error->message);
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+class GIOUTF8StringEnumerator final : public nsIUTF8StringEnumerator
+{
+ ~GIOUTF8StringEnumerator() { }
+
+public:
+ GIOUTF8StringEnumerator() : mIndex(0) { }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIUTF8STRINGENUMERATOR
+
+ nsTArray<nsCString> mStrings;
+ uint32_t mIndex;
+};
+
+NS_IMPL_ISUPPORTS(GIOUTF8StringEnumerator, nsIUTF8StringEnumerator)
+
+NS_IMETHODIMP
+GIOUTF8StringEnumerator::HasMore(bool* aResult)
+{
+ *aResult = mIndex < mStrings.Length();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GIOUTF8StringEnumerator::GetNext(nsACString& aResult)
+{
+ if (mIndex >= mStrings.Length())
+ return NS_ERROR_UNEXPECTED;
+
+ aResult.Assign(mStrings[mIndex]);
+ ++mIndex;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::GetSupportedURISchemes(nsIUTF8StringEnumerator** aSchemes)
+{
+ *aSchemes = nullptr;
+
+ RefPtr<GIOUTF8StringEnumerator> array = new GIOUTF8StringEnumerator();
+ NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
+
+ GVfs *gvfs = g_vfs_get_default();
+
+ if (!gvfs) {
+ g_warning("Cannot get GVfs object.");
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ const gchar* const * uri_schemes = g_vfs_get_supported_uri_schemes(gvfs);
+
+ while (*uri_schemes != nullptr) {
+ if (!array->mStrings.AppendElement(*uri_schemes)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ uri_schemes++;
+ }
+
+ array.forget(aSchemes);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::SetAsDefaultForMimeType(nsACString const& aMimeType)
+{
+ char *content_type =
+ g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
+ if (!content_type)
+ return NS_ERROR_FAILURE;
+ GError *error = nullptr;
+ g_app_info_set_as_default_for_type(mApp,
+ content_type,
+ &error);
+ if (error) {
+ g_warning("Cannot set application as default for MIME type (%s): %s",
+ PromiseFlatCString(aMimeType).get(),
+ error->message);
+ g_error_free(error);
+ g_free(content_type);
+ return NS_ERROR_FAILURE;
+ }
+
+ g_free(content_type);
+ return NS_OK;
+}
+/**
+ * Set default application for files with given extensions
+ * @param fileExts string of space separated extensions
+ * @return NS_OK when application was set as default for given extensions,
+ * NS_ERROR_FAILURE otherwise
+ */
+NS_IMETHODIMP
+nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts)
+{
+ GError *error = nullptr;
+ char *extensions = g_strdup(PromiseFlatCString(fileExts).get());
+ char *ext_pos = extensions;
+ char *space_pos;
+
+ while ( (space_pos = strchr(ext_pos, ' ')) || (*ext_pos != '\0') ) {
+ if (space_pos) {
+ *space_pos = '\0';
+ }
+ g_app_info_set_as_default_for_extension(mApp, ext_pos, &error);
+ if (error) {
+ g_warning("Cannot set application as default for extension (%s): %s",
+ ext_pos,
+ error->message);
+ g_error_free(error);
+ g_free(extensions);
+ return NS_ERROR_FAILURE;
+ }
+ if (space_pos) {
+ ext_pos = space_pos + 1;
+ } else {
+ *ext_pos = '\0';
+ }
+ }
+ g_free(extensions);
+ return NS_OK;
+}
+
+/**
+ * Set default application for URI's of a particular scheme
+ * @param aURIScheme string containing the URI scheme
+ * @return NS_OK when application was set as default for URI scheme,
+ * NS_ERROR_FAILURE otherwise
+ */
+NS_IMETHODIMP
+nsGIOMimeApp::SetAsDefaultForURIScheme(nsACString const& aURIScheme)
+{
+ GError *error = nullptr;
+ nsAutoCString contentType("x-scheme-handler/");
+ contentType.Append(aURIScheme);
+
+ g_app_info_set_as_default_for_type(mApp,
+ contentType.get(),
+ &error);
+ if (error) {
+ g_warning("Cannot set application as default for URI scheme (%s): %s",
+ PromiseFlatCString(aURIScheme).get(),
+ error->message);
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsGIOService, nsIGIOService)
+
+NS_IMETHODIMP
+nsGIOService::GetMimeTypeFromExtension(const nsACString& aExtension,
+ nsACString& aMimeType)
+{
+ nsAutoCString fileExtToUse("file.");
+ fileExtToUse.Append(aExtension);
+
+ gboolean result_uncertain;
+ char *content_type = g_content_type_guess(fileExtToUse.get(),
+ nullptr,
+ 0,
+ &result_uncertain);
+ if (!content_type)
+ return NS_ERROR_FAILURE;
+
+ char *mime_type = g_content_type_get_mime_type(content_type);
+ if (!mime_type) {
+ g_free(content_type);
+ return NS_ERROR_FAILURE;
+ }
+
+ aMimeType.Assign(mime_type);
+
+ g_free(mime_type);
+ g_free(content_type);
+
+ return NS_OK;
+}
+// used in nsGNOMERegistry
+// -----------------------------------------------------------------------------
+NS_IMETHODIMP
+nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme,
+ nsIGIOMimeApp** aApp)
+{
+ *aApp = nullptr;
+
+ GAppInfo *app_info = g_app_info_get_default_for_uri_scheme(
+ PromiseFlatCString(aURIScheme).get());
+ if (app_info) {
+ nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
+ NS_ADDREF(*aApp = mozApp);
+ } else {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
+ nsIGIOMimeApp** aApp)
+{
+ *aApp = nullptr;
+ char *content_type =
+ g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
+ if (!content_type)
+ return NS_ERROR_FAILURE;
+
+ GAppInfo *app_info = g_app_info_get_default_for_type(content_type, false);
+ if (app_info) {
+ nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
+ NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
+ NS_ADDREF(*aApp = mozApp);
+ } else {
+ g_free(content_type);
+ return NS_ERROR_FAILURE;
+ }
+ g_free(content_type);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOService::GetDescriptionForMimeType(const nsACString& aMimeType,
+ nsACString& aDescription)
+{
+ char *content_type =
+ g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
+ if (!content_type)
+ return NS_ERROR_FAILURE;
+
+ char *desc = g_content_type_get_description(content_type);
+ if (!desc) {
+ g_free(content_type);
+ return NS_ERROR_FAILURE;
+ }
+
+ aDescription.Assign(desc);
+ g_free(content_type);
+ g_free(desc);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOService::ShowURI(nsIURI* aURI)
+{
+ nsAutoCString spec;
+ nsresult rv = aURI->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+ GError *error = nullptr;
+ if (!g_app_info_launch_default_for_uri(spec.get(), nullptr, &error)) {
+ g_warning("Could not launch default application for URI: %s", error->message);
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOService::ShowURIForInput(const nsACString& aUri)
+{
+ GFile *file = g_file_new_for_commandline_arg(PromiseFlatCString(aUri).get());
+ char* spec = g_file_get_uri(file);
+ nsresult rv = NS_ERROR_FAILURE;
+ GError *error = nullptr;
+
+ g_app_info_launch_default_for_uri(spec, nullptr, &error);
+ if (error) {
+ g_warning("Cannot launch default application: %s", error->message);
+ g_error_free(error);
+ } else {
+ rv = NS_OK;
+ }
+ g_object_unref(file);
+ g_free(spec);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath)
+{
+#ifndef MOZ_ENABLE_DBUS
+ return NS_ERROR_FAILURE;
+#else
+ GError* error = nullptr;
+ static bool org_freedesktop_FileManager1_exists = true;
+
+ if (!org_freedesktop_FileManager1_exists) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ DBusGConnection* dbusGConnection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (!dbusGConnection) {
+ if (error) {
+ g_printerr("Failed to open connection to session bus: %s\n", error->message);
+ g_error_free(error);
+ }
+ return NS_ERROR_FAILURE;
+ }
+
+ char *uri = g_filename_to_uri(PromiseFlatCString(aPath).get(), nullptr, nullptr);
+ if (uri == nullptr) {
+ return NS_ERROR_FAILURE;
+ }
+
+ DBusConnection* dbusConnection = dbus_g_connection_get_connection(dbusGConnection);
+ // Make sure we do not exit the entire program if DBus connection get lost.
+ dbus_connection_set_exit_on_disconnect(dbusConnection, false);
+
+ DBusGProxy* dbusGProxy = dbus_g_proxy_new_for_name(dbusGConnection,
+ "org.freedesktop.FileManager1",
+ "/org/freedesktop/FileManager1",
+ "org.freedesktop.FileManager1");
+
+ const char *uris[2] = { uri, nullptr };
+ gboolean rv_dbus_call = dbus_g_proxy_call (dbusGProxy, "ShowItems", nullptr, G_TYPE_STRV, uris,
+ G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
+
+ g_object_unref(dbusGProxy);
+ dbus_g_connection_unref(dbusGConnection);
+ g_free(uri);
+
+ if (!rv_dbus_call) {
+ org_freedesktop_FileManager1_exists = false;
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ return NS_OK;
+#endif
+}
+
+/**
+ * Create or find already existing application info for specified command
+ * and application name.
+ * @param cmd command to execute
+ * @param appName application name
+ * @param appInfo location where created GAppInfo is stored
+ * @return NS_OK when object is created, NS_ERROR_FAILURE otherwise.
+ */
+NS_IMETHODIMP
+nsGIOService::CreateAppFromCommand(nsACString const& cmd,
+ nsACString const& appName,
+ nsIGIOMimeApp** appInfo)
+{
+ GError *error = nullptr;
+ *appInfo = nullptr;
+
+ GAppInfo *app_info = nullptr, *app_info_from_list = nullptr;
+ GList *apps = g_app_info_get_all();
+ GList *apps_p = apps;
+
+ // Try to find relevant and existing GAppInfo in all installed application
+ // We do this by comparing each GAppInfo's executable with out own
+ while (apps_p) {
+ app_info_from_list = (GAppInfo*) apps_p->data;
+ if (!app_info) {
+ // If the executable is not absolute, get it's full path
+ char *executable = g_find_program_in_path(g_app_info_get_executable(app_info_from_list));
+
+ if (executable && strcmp(executable, PromiseFlatCString(cmd).get()) == 0) {
+ g_object_ref (app_info_from_list);
+ app_info = app_info_from_list;
+ }
+ g_free(executable);
+ }
+
+ g_object_unref(app_info_from_list);
+ apps_p = apps_p->next;
+ }
+ g_list_free(apps);
+
+ if (!app_info) {
+ app_info = g_app_info_create_from_commandline(PromiseFlatCString(cmd).get(),
+ PromiseFlatCString(appName).get(),
+ G_APP_INFO_CREATE_SUPPORTS_URIS,
+ &error);
+ }
+
+ if (!app_info) {
+ g_warning("Cannot create application info from command: %s", error->message);
+ g_error_free(error);
+ return NS_ERROR_FAILURE;
+ }
+ nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
+ NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
+ NS_ADDREF(*appInfo = mozApp);
+ return NS_OK;
+}
diff --git a/toolkit/system/gnome/nsGIOService.h b/toolkit/system/gnome/nsGIOService.h
new file mode 100644
index 000000000..2ae7a7e1a
--- /dev/null
+++ b/toolkit/system/gnome/nsGIOService.h
@@ -0,0 +1,24 @@
+/* -*- 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 nsGIOService_h_
+#define nsGIOService_h_
+
+#include "nsIGIOService.h"
+
+#define NS_GIOSERVICE_CID \
+{0xe3a1f3c9, 0x3ae1, 0x4b40, {0xa5, 0xe0, 0x7b, 0x45, 0x7f, 0xc9, 0xa9, 0xad}}
+
+class nsGIOService final : public nsIGIOService
+{
+ ~nsGIOService() {}
+
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGIOSERVICE
+};
+
+#endif
+
diff --git a/toolkit/system/gnome/nsGSettingsService.cpp b/toolkit/system/gnome/nsGSettingsService.cpp
new file mode 100644
index 000000000..d8c46b4fe
--- /dev/null
+++ b/toolkit/system/gnome/nsGSettingsService.cpp
@@ -0,0 +1,350 @@
+/* -*- 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/ArrayUtils.h"
+
+#include "nsGSettingsService.h"
+#include "nsString.h"
+#include "nsCOMPtr.h"
+#include "nsMemory.h"
+#include "prlink.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIMutableArray.h"
+#include "nsISupportsPrimitives.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+using namespace mozilla;
+
+typedef struct _GSettings GSettings;
+typedef struct _GVariantType GVariantType;
+typedef struct _GVariant GVariant;
+
+#ifndef G_VARIANT_TYPE_INT32
+# define G_VARIANT_TYPE_INT32 ((const GVariantType *) "i")
+# define G_VARIANT_TYPE_BOOLEAN ((const GVariantType *) "b")
+# define G_VARIANT_TYPE_STRING ((const GVariantType *) "s")
+# define G_VARIANT_TYPE_OBJECT_PATH ((const GVariantType *) "o")
+# define G_VARIANT_TYPE_SIGNATURE ((const GVariantType *) "g")
+#endif
+#ifndef G_VARIANT_TYPE_STRING_ARRAY
+# define G_VARIANT_TYPE_STRING_ARRAY ((const GVariantType *) "as")
+#endif
+
+#define GSETTINGS_FUNCTIONS \
+ FUNC(g_settings_new, GSettings *, (const char* schema)) \
+ FUNC(g_settings_list_schemas, const char * const *, (void)) \
+ FUNC(g_settings_list_keys, char **, (GSettings* settings)) \
+ FUNC(g_settings_get_value, GVariant *, (GSettings* settings, const char* key)) \
+ FUNC(g_settings_set_value, gboolean, (GSettings* settings, const char* key, GVariant* value)) \
+ FUNC(g_settings_range_check, gboolean, (GSettings* settings, const char* key, GVariant* value)) \
+ FUNC(g_variant_get_int32, gint32, (GVariant* variant)) \
+ FUNC(g_variant_get_boolean, gboolean, (GVariant* variant)) \
+ FUNC(g_variant_get_string, const char *, (GVariant* value, gsize* length)) \
+ FUNC(g_variant_get_strv, const char **, (GVariant* value, gsize* length)) \
+ FUNC(g_variant_is_of_type, gboolean, (GVariant* value, const GVariantType* type)) \
+ FUNC(g_variant_new_int32, GVariant *, (gint32 value)) \
+ FUNC(g_variant_new_boolean, GVariant *, (gboolean value)) \
+ FUNC(g_variant_new_string, GVariant *, (const char* string)) \
+ FUNC(g_variant_unref, void, (GVariant* value))
+
+#define FUNC(name, type, params) \
+ typedef type (*_##name##_fn) params; \
+ static _##name##_fn _##name;
+
+GSETTINGS_FUNCTIONS
+
+#undef FUNC
+
+#define g_settings_new _g_settings_new
+#define g_settings_list_schemas _g_settings_list_schemas
+#define g_settings_list_keys _g_settings_list_keys
+#define g_settings_get_value _g_settings_get_value
+#define g_settings_set_value _g_settings_set_value
+#define g_settings_range_check _g_settings_range_check
+#define g_variant_get_int32 _g_variant_get_int32
+#define g_variant_get_boolean _g_variant_get_boolean
+#define g_variant_get_string _g_variant_get_string
+#define g_variant_get_strv _g_variant_get_strv
+#define g_variant_is_of_type _g_variant_is_of_type
+#define g_variant_new_int32 _g_variant_new_int32
+#define g_variant_new_boolean _g_variant_new_boolean
+#define g_variant_new_string _g_variant_new_string
+#define g_variant_unref _g_variant_unref
+
+static PRLibrary *gioLib = nullptr;
+
+class nsGSettingsCollection final : public nsIGSettingsCollection
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGSETTINGSCOLLECTION
+
+ explicit nsGSettingsCollection(GSettings* aSettings) : mSettings(aSettings),
+ mKeys(nullptr) {}
+private:
+ ~nsGSettingsCollection();
+
+ bool KeyExists(const nsACString& aKey);
+ bool SetValue(const nsACString& aKey,
+ GVariant *aValue);
+
+ GSettings *mSettings;
+ char **mKeys;
+};
+
+nsGSettingsCollection::~nsGSettingsCollection()
+{
+ g_strfreev(mKeys);
+ g_object_unref(mSettings);
+}
+
+bool
+nsGSettingsCollection::KeyExists(const nsACString& aKey)
+{
+ if (!mKeys)
+ mKeys = g_settings_list_keys(mSettings);
+
+ for (uint32_t i = 0; mKeys[i] != nullptr; i++) {
+ if (aKey.Equals(mKeys[i]))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+nsGSettingsCollection::SetValue(const nsACString& aKey,
+ GVariant *aValue)
+{
+ if (!KeyExists(aKey) ||
+ !g_settings_range_check(mSettings,
+ PromiseFlatCString(aKey).get(),
+ aValue)) {
+ g_variant_unref(aValue);
+ return false;
+ }
+
+ return g_settings_set_value(mSettings,
+ PromiseFlatCString(aKey).get(),
+ aValue);
+}
+
+NS_IMPL_ISUPPORTS(nsGSettingsCollection, nsIGSettingsCollection)
+
+NS_IMETHODIMP
+nsGSettingsCollection::SetString(const nsACString& aKey,
+ const nsACString& aValue)
+{
+ GVariant *value = g_variant_new_string(PromiseFlatCString(aValue).get());
+ if (!value)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ bool res = SetValue(aKey, value);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGSettingsCollection::SetBoolean(const nsACString& aKey,
+ bool aValue)
+{
+ GVariant *value = g_variant_new_boolean(aValue);
+ if (!value)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ bool res = SetValue(aKey, value);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGSettingsCollection::SetInt(const nsACString& aKey,
+ int32_t aValue)
+{
+ GVariant *value = g_variant_new_int32(aValue);
+ if (!value)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ bool res = SetValue(aKey, value);
+
+ return res ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsGSettingsCollection::GetString(const nsACString& aKey,
+ nsACString& aResult)
+{
+ if (!KeyExists(aKey))
+ return NS_ERROR_INVALID_ARG;
+
+ GVariant *value = g_settings_get_value(mSettings,
+ PromiseFlatCString(aKey).get());
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) &&
+ !g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH) &&
+ !g_variant_is_of_type(value, G_VARIANT_TYPE_SIGNATURE)) {
+ g_variant_unref(value);
+ return NS_ERROR_FAILURE;
+ }
+
+ aResult.Assign(g_variant_get_string(value, nullptr));
+ g_variant_unref(value);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGSettingsCollection::GetBoolean(const nsACString& aKey,
+ bool* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ if (!KeyExists(aKey))
+ return NS_ERROR_INVALID_ARG;
+
+ GVariant *value = g_settings_get_value(mSettings,
+ PromiseFlatCString(aKey).get());
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
+ g_variant_unref(value);
+ return NS_ERROR_FAILURE;
+ }
+
+ gboolean res = g_variant_get_boolean(value);
+ *aResult = res ? true : false;
+ g_variant_unref(value);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGSettingsCollection::GetInt(const nsACString& aKey,
+ int32_t* aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ if (!KeyExists(aKey))
+ return NS_ERROR_INVALID_ARG;
+
+ GVariant *value = g_settings_get_value(mSettings,
+ PromiseFlatCString(aKey).get());
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
+ g_variant_unref(value);
+ return NS_ERROR_FAILURE;
+ }
+
+ *aResult = g_variant_get_int32(value);
+ g_variant_unref(value);
+
+ return NS_OK;
+}
+
+// These types are local to nsGSettingsService::Init, but ISO C++98 doesn't
+// allow a template (ArrayLength) to be instantiated based on a local type.
+// Boo-urns!
+typedef void (*nsGSettingsFunc)();
+struct nsGSettingsDynamicFunction {
+ const char *functionName;
+ nsGSettingsFunc *function;
+};
+
+NS_IMETHODIMP
+nsGSettingsCollection::GetStringList(const nsACString& aKey, nsIArray** aResult)
+{
+ if (!KeyExists(aKey))
+ return NS_ERROR_INVALID_ARG;
+
+ nsCOMPtr<nsIMutableArray> items(do_CreateInstance(NS_ARRAY_CONTRACTID));
+ if (!items) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ GVariant *value = g_settings_get_value(mSettings,
+ PromiseFlatCString(aKey).get());
+
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) {
+ g_variant_unref(value);
+ return NS_ERROR_FAILURE;
+ }
+
+ const gchar ** gs_strings = g_variant_get_strv(value, nullptr);
+ if (!gs_strings) {
+ // empty array
+ items.forget(aResult);
+ g_variant_unref(value);
+ return NS_OK;
+ }
+
+ const gchar** p_gs_strings = gs_strings;
+ while (*p_gs_strings != nullptr)
+ {
+ nsCOMPtr<nsISupportsCString> obj(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
+ if (obj) {
+ obj->SetData(nsDependentCString(*p_gs_strings));
+ items->AppendElement(obj, false);
+ }
+ p_gs_strings++;
+ }
+ g_free(gs_strings);
+ items.forget(aResult);
+ g_variant_unref(value);
+ return NS_OK;
+}
+
+nsresult
+nsGSettingsService::Init()
+{
+#define FUNC(name, type, params) { #name, (nsGSettingsFunc *)&_##name },
+ static const nsGSettingsDynamicFunction kGSettingsSymbols[] = {
+ GSETTINGS_FUNCTIONS
+ };
+#undef FUNC
+
+ if (!gioLib) {
+ gioLib = PR_LoadLibrary("libgio-2.0.so.0");
+ if (!gioLib)
+ return NS_ERROR_FAILURE;
+ }
+
+ for (uint32_t i = 0; i < ArrayLength(kGSettingsSymbols); i++) {
+ *kGSettingsSymbols[i].function =
+ PR_FindFunctionSymbol(gioLib, kGSettingsSymbols[i].functionName);
+ if (!*kGSettingsSymbols[i].function) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsGSettingsService, nsIGSettingsService)
+
+nsGSettingsService::~nsGSettingsService()
+{
+ if (gioLib) {
+ PR_UnloadLibrary(gioLib);
+ gioLib = nullptr;
+ }
+}
+
+NS_IMETHODIMP
+nsGSettingsService::GetCollectionForSchema(const nsACString& schema,
+ nsIGSettingsCollection** collection)
+{
+ NS_ENSURE_ARG_POINTER(collection);
+
+ const char * const *schemas = g_settings_list_schemas();
+
+ for (uint32_t i = 0; schemas[i] != nullptr; i++) {
+ if (schema.Equals(schemas[i])) {
+ GSettings *settings = g_settings_new(PromiseFlatCString(schema).get());
+ nsGSettingsCollection *mozGSettings = new nsGSettingsCollection(settings);
+ NS_ADDREF(*collection = mozGSettings);
+ return NS_OK;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
diff --git a/toolkit/system/gnome/nsGSettingsService.h b/toolkit/system/gnome/nsGSettingsService.h
new file mode 100644
index 000000000..6ffcdedd1
--- /dev/null
+++ b/toolkit/system/gnome/nsGSettingsService.h
@@ -0,0 +1,27 @@
+/* -*- 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 nsGSettingsService_h_
+#define nsGSettingsService_h_
+
+#include "nsIGSettingsService.h"
+
+#define NS_GSETTINGSSERVICE_CID \
+{0xbfd4a9d8, 0xd886, 0x4161, {0x81, 0xef, 0x88, 0x68, 0xda, 0x11, 0x41, 0x70}}
+
+class nsGSettingsService final : public nsIGSettingsService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGSETTINGSSERVICE
+
+ nsresult Init();
+
+private:
+ ~nsGSettingsService();
+};
+
+#endif
+
diff --git a/toolkit/system/gnome/nsGnomeModule.cpp b/toolkit/system/gnome/nsGnomeModule.cpp
new file mode 100644
index 000000000..6ecebcc1f
--- /dev/null
+++ b/toolkit/system/gnome/nsGnomeModule.cpp
@@ -0,0 +1,78 @@
+/* -*- 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 "nsToolkitCompsCID.h"
+#include "mozilla/ModuleUtils.h"
+
+#include <glib-object.h>
+
+#ifdef MOZ_ENABLE_GCONF
+#include "nsGConfService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGConfService, Init)
+#endif
+#ifdef MOZ_ENABLE_GIO
+#include "nsGIOService.h"
+#include "nsGSettingsService.h"
+#include "nsPackageKitService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIOService)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGSettingsService, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPackageKitService, Init)
+#endif
+#include "nsSystemAlertsService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemAlertsService, Init)
+
+#ifdef MOZ_ENABLE_GCONF
+NS_DEFINE_NAMED_CID(NS_GCONFSERVICE_CID);
+#endif
+#ifdef MOZ_ENABLE_GIO
+NS_DEFINE_NAMED_CID(NS_GIOSERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_GSETTINGSSERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_PACKAGEKITSERVICE_CID);
+#endif
+NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID);
+
+static const mozilla::Module::CIDEntry kGnomeCIDs[] = {
+#ifdef MOZ_ENABLE_GCONF
+ { &kNS_GCONFSERVICE_CID, false, nullptr, nsGConfServiceConstructor },
+#endif
+#ifdef MOZ_ENABLE_GIO
+ { &kNS_GIOSERVICE_CID, false, nullptr, nsGIOServiceConstructor },
+ { &kNS_GSETTINGSSERVICE_CID, false, nullptr, nsGSettingsServiceConstructor },
+ { &kNS_PACKAGEKITSERVICE_CID, false, nullptr, nsPackageKitServiceConstructor },
+#endif
+ { &kNS_SYSTEMALERTSSERVICE_CID, false, nullptr, nsSystemAlertsServiceConstructor },
+ { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kGnomeContracts[] = {
+#ifdef MOZ_ENABLE_GCONF
+ { NS_GCONFSERVICE_CONTRACTID, &kNS_GCONFSERVICE_CID },
+#endif
+#ifdef MOZ_ENABLE_GIO
+ { NS_GIOSERVICE_CONTRACTID, &kNS_GIOSERVICE_CID },
+ { NS_GSETTINGSSERVICE_CONTRACTID, &kNS_GSETTINGSSERVICE_CID },
+ { NS_PACKAGEKITSERVICE_CONTRACTID, &kNS_PACKAGEKITSERVICE_CID },
+#endif
+ { NS_SYSTEMALERTSERVICE_CONTRACTID, &kNS_SYSTEMALERTSSERVICE_CID },
+ { nullptr }
+};
+
+static nsresult
+InitGType ()
+{
+ g_type_init();
+ return NS_OK;
+}
+
+static const mozilla::Module kGnomeModule = {
+ mozilla::Module::kVersion,
+ kGnomeCIDs,
+ kGnomeContracts,
+ nullptr,
+ nullptr,
+ InitGType
+};
+
+NSMODULE_DEFN(mozgnome) = &kGnomeModule;
diff --git a/toolkit/system/gnome/nsPackageKitService.cpp b/toolkit/system/gnome/nsPackageKitService.cpp
new file mode 100644
index 000000000..c32a91367
--- /dev/null
+++ b/toolkit/system/gnome/nsPackageKitService.cpp
@@ -0,0 +1,267 @@
+/* -*- 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 "nsArrayUtils.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsISupportsPrimitives.h"
+#include "nsPackageKitService.h"
+#include "nsString.h"
+#include "prlink.h"
+#include "mozilla/Unused.h"
+#include "mozilla/UniquePtr.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <limits>
+
+using namespace mozilla;
+
+typedef struct _GAsyncResult GAsyncResult;
+typedef enum {
+ G_BUS_TYPE_STARTER = -1,
+ G_BUS_TYPE_NONE = 0,
+ G_BUS_TYPE_SYSTEM = 1,
+ G_BUS_TYPE_SESSION = 2
+} GBusType;
+typedef struct _GCancellable GCancellable;
+typedef enum {
+ G_DBUS_CALL_FLAGS_NONE = 0,
+ G_DBUS_CALL_FLAGS_NO_AUTO_START = (1<<0)
+} GDBusCallFlags;
+typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo;
+typedef struct _GDBusProxy GDBusProxy;
+typedef enum {
+ G_DBUS_PROXY_FLAGS_NONE = 0,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0),
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1),
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2),
+ G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES = (1<<3)
+} GDBusProxyFlags;
+typedef struct _GVariant GVariant;
+typedef void (*GAsyncReadyCallback) (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data);
+
+#define GDBUS_FUNCTIONS \
+ FUNC(g_dbus_proxy_call, void, (GDBusProxy *proxy, const gchar *method_name, GVariant *parameters, GDBusCallFlags flags, gint timeout_msec, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)) \
+ FUNC(g_dbus_proxy_call_finish, GVariant*, (GDBusProxy *proxy, GAsyncResult *res, GError **error)) \
+ FUNC(g_dbus_proxy_new_finish, GDBusProxy*, (GAsyncResult *res, GError **error)) \
+ FUNC(g_dbus_proxy_new_for_bus, void, (GBusType bus_type, GDBusProxyFlags flags, GDBusInterfaceInfo *info, const gchar *name, const gchar *object_path, const gchar *interface_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)) \
+ FUNC(g_variant_is_floating, gboolean, (GVariant *value)) \
+ FUNC(g_variant_new, GVariant*, (const gchar *format_string, ...)) \
+ FUNC(g_variant_unref, void, (GVariant* value))
+
+#define FUNC(name, type, params) \
+ typedef type (*_##name##_fn) params; \
+ static _##name##_fn _##name;
+
+GDBUS_FUNCTIONS
+
+#undef FUNC
+
+#define g_dbus_proxy_call _g_dbus_proxy_call
+#define g_dbus_proxy_call_finish _g_dbus_proxy_call_finish
+#define g_dbus_proxy_new_finish _g_dbus_proxy_new_finish
+#define g_dbus_proxy_new_for_bus _g_dbus_proxy_new_for_bus
+#define g_variant_is_floating _g_variant_is_floating
+#define g_variant_new _g_variant_new
+#define g_variant_unref _g_variant_unref
+
+static PRLibrary *gioLib = nullptr;
+
+typedef void (*nsGDBusFunc)();
+struct nsGDBusDynamicFunction {
+ const char *functionName;
+ nsGDBusFunc *function;
+};
+
+nsresult
+nsPackageKitService::Init()
+{
+#define FUNC(name, type, params) { #name, (nsGDBusFunc *)&_##name },
+ const nsGDBusDynamicFunction kGDBusSymbols[] = {
+ GDBUS_FUNCTIONS
+ };
+#undef FUNC
+
+ if (!gioLib) {
+ gioLib = PR_LoadLibrary("libgio-2.0.so.0");
+ if (!gioLib)
+ return NS_ERROR_FAILURE;
+ }
+
+ for (uint32_t i = 0; i < ArrayLength(kGDBusSymbols); i++) {
+ *kGDBusSymbols[i].function =
+ PR_FindFunctionSymbol(gioLib, kGDBusSymbols[i].functionName);
+ if (!*kGDBusSymbols[i].function) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsPackageKitService, nsIPackageKitService)
+
+nsPackageKitService::~nsPackageKitService()
+{
+ if (gioLib) {
+ PR_UnloadLibrary(gioLib);
+ gioLib = nullptr;
+ }
+}
+
+static const char* InstallPackagesMethods[] = {
+ "InstallPackageNames",
+ "InstallMimeTypes",
+ "InstallFontconfigResources",
+ "InstallGStreamerResources"
+};
+
+struct InstallPackagesProxyNewData {
+ nsCOMPtr<nsIObserver> observer;
+ uint32_t method;
+ GVariant* parameters;
+};
+
+static void
+InstallPackagesNotifyObserver(nsIObserver* aObserver,
+ gchar* aErrorMessage)
+{
+ if (aObserver) {
+ aObserver->Observe(nullptr, "packagekit-install",
+ aErrorMessage ?
+ NS_ConvertUTF8toUTF16(aErrorMessage).get() :
+ nullptr);
+ }
+}
+
+static void
+InstallPackagesProxyCallCallback(GObject *aSourceObject,
+ GAsyncResult *aResult,
+ gpointer aUserData)
+{
+ nsCOMPtr<nsIObserver> observer = static_cast<nsIObserver*>(aUserData);
+ GDBusProxy* proxy = reinterpret_cast<GDBusProxy*>(aSourceObject);
+
+ GError* error = nullptr;
+ GVariant* result = g_dbus_proxy_call_finish(proxy, aResult, &error);
+ if (result) {
+ InstallPackagesNotifyObserver(observer, nullptr);
+ g_variant_unref(result);
+ } else {
+ NS_ASSERTION(error, "g_dbus_proxy_call_finish should set error when it returns NULL");
+ InstallPackagesNotifyObserver(observer, error->message);
+ g_error_free(error);
+ }
+
+ g_object_unref(proxy);
+ Unused << observer.forget().take();
+}
+
+static void
+InstallPackagesProxyNewCallback(GObject *aSourceObject,
+ GAsyncResult *aResult,
+ gpointer aUserData)
+{
+ InstallPackagesProxyNewData* userData =
+ static_cast<InstallPackagesProxyNewData*>(aUserData);
+
+ NS_ASSERTION(g_variant_is_floating(userData->parameters),
+ "userData->parameters should be a floating reference.");
+
+ GError* error = nullptr;
+ GDBusProxy* proxy = g_dbus_proxy_new_finish(aResult, &error);
+
+ if (proxy) {
+ // Send the asynchronous request to install the packages
+ // This call will consume the floating reference userData->parameters so we
+ // don't need to release it explicitly.
+ nsIObserver* observer;
+ userData->observer.forget(&observer);
+ g_dbus_proxy_call(proxy,
+ InstallPackagesMethods[userData->method],
+ userData->parameters,
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ nullptr,
+ &InstallPackagesProxyCallCallback,
+ static_cast<gpointer>(observer));
+ } else {
+ NS_ASSERTION(error, "g_dbus_proxy_new_finish should set error when it returns NULL");
+ InstallPackagesNotifyObserver(userData->observer, error->message);
+ g_error_free(error);
+ g_variant_unref(userData->parameters);
+ }
+ delete userData;
+}
+
+NS_IMETHODIMP
+nsPackageKitService::InstallPackages(uint32_t aInstallMethod,
+ nsIArray* aPackageArray,
+ nsIObserver* aObserver)
+{
+ NS_ENSURE_ARG(aPackageArray);
+
+ uint32_t arrayLength;
+ aPackageArray->GetLength(&arrayLength);
+ if (arrayLength == 0 ||
+ arrayLength == std::numeric_limits<uint32_t>::max() ||
+ aInstallMethod >= PK_INSTALL_METHOD_COUNT) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Create the GVariant* parameter from the list of packages.
+ GVariant* parameters = nullptr;
+ auto packages = MakeUnique<gchar*[]>(arrayLength + 1);
+
+ nsresult rv = NS_OK;
+ for (uint32_t i = 0; i < arrayLength; i++) {
+ nsCOMPtr<nsISupportsString> package =
+ do_QueryElementAt(aPackageArray, i);
+ if (!package) {
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
+ nsString data;
+ package->GetData(data);
+ packages[i] = g_strdup(NS_ConvertUTF16toUTF8(data).get());
+ if (!packages[i]) {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ break;
+ }
+ }
+ packages[arrayLength] = nullptr;
+
+ if (NS_SUCCEEDED(rv)) {
+ // We create a new GVariant object to send parameters to PackageKit.
+ parameters = g_variant_new("(u^ass)", static_cast<guint32>(0),
+ packages.get(), "hide-finished");
+ if (!parameters) {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ for (uint32_t i = 0; i < arrayLength; i++) {
+ g_free(packages[i]);
+ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Send the asynchronous request to load the bus proxy
+ InstallPackagesProxyNewData* data = new InstallPackagesProxyNewData;
+ data->observer = aObserver;
+ data->method = aInstallMethod;
+ data->parameters = parameters;
+ g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ nullptr,
+ "org.freedesktop.PackageKit",
+ "/org/freedesktop/PackageKit",
+ "org.freedesktop.PackageKit.Modify",
+ nullptr,
+ &InstallPackagesProxyNewCallback,
+ static_cast<gpointer>(data));
+ return NS_OK;
+}
diff --git a/toolkit/system/gnome/nsPackageKitService.h b/toolkit/system/gnome/nsPackageKitService.h
new file mode 100644
index 000000000..b14c7c51f
--- /dev/null
+++ b/toolkit/system/gnome/nsPackageKitService.h
@@ -0,0 +1,26 @@
+/* -*- 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 nsPackageKitService_h_
+#define nsPackageKitService_h_
+
+#include "nsIPackageKitService.h"
+
+#define NS_PACKAGEKITSERVICE_CID \
+{0x9c95515e, 0x611d, 0x11e4, {0xb9, 0x7e, 0x60, 0xa4, 0x4c, 0x71, 0x70, 0x42}}
+
+class nsPackageKitService final : public nsIPackageKitService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPACKAGEKITSERVICE
+
+ nsresult Init();
+
+private:
+ ~nsPackageKitService();
+};
+
+#endif
diff --git a/toolkit/system/gnome/nsSystemAlertsService.cpp b/toolkit/system/gnome/nsSystemAlertsService.cpp
new file mode 100644
index 000000000..2af64383c
--- /dev/null
+++ b/toolkit/system/gnome/nsSystemAlertsService.cpp
@@ -0,0 +1,118 @@
+/* -*- 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 "nsComponentManagerUtils.h"
+#include "nsXULAppAPI.h"
+#include "nsSystemAlertsService.h"
+#include "nsAlertsIconListener.h"
+#include "nsAutoPtr.h"
+
+NS_IMPL_ADDREF(nsSystemAlertsService)
+NS_IMPL_RELEASE(nsSystemAlertsService)
+
+NS_INTERFACE_MAP_BEGIN(nsSystemAlertsService)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAlertsService)
+ NS_INTERFACE_MAP_ENTRY(nsIAlertsService)
+NS_INTERFACE_MAP_END_THREADSAFE
+
+nsSystemAlertsService::nsSystemAlertsService()
+{
+}
+
+nsSystemAlertsService::~nsSystemAlertsService()
+{}
+
+nsresult
+nsSystemAlertsService::Init()
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsSystemAlertsService::ShowAlertNotification(const nsAString & aImageUrl, const nsAString & aAlertTitle,
+ const nsAString & aAlertText, bool aAlertTextClickable,
+ const nsAString & aAlertCookie,
+ nsIObserver * aAlertListener,
+ const nsAString & aAlertName,
+ const nsAString & aBidi,
+ const nsAString & aLang,
+ const nsAString & aData,
+ nsIPrincipal * aPrincipal,
+ bool aInPrivateBrowsing,
+ bool aRequireInteraction)
+{
+ nsCOMPtr<nsIAlertNotification> alert =
+ do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
+ NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
+ nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
+ aAlertText, aAlertTextClickable,
+ aAlertCookie, aBidi, aLang, aData,
+ aPrincipal, aInPrivateBrowsing,
+ aRequireInteraction);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return ShowAlert(alert, aAlertListener);
+}
+
+NS_IMETHODIMP nsSystemAlertsService::ShowPersistentNotification(const nsAString& aPersistentData,
+ nsIAlertNotification* aAlert,
+ nsIObserver* aAlertListener)
+{
+ return ShowAlert(aAlert, aAlertListener);
+}
+
+NS_IMETHODIMP nsSystemAlertsService::ShowAlert(nsIAlertNotification* aAlert,
+ nsIObserver* aAlertListener)
+{
+ NS_ENSURE_ARG(aAlert);
+
+ nsAutoString alertName;
+ nsresult rv = aAlert->GetName(alertName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<nsAlertsIconListener> alertListener =
+ new nsAlertsIconListener(this, alertName);
+ if (!alertListener)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ AddListener(alertName, alertListener);
+ return alertListener->InitAlertAsync(aAlert, aAlertListener);
+}
+
+NS_IMETHODIMP nsSystemAlertsService::CloseAlert(const nsAString& aAlertName,
+ nsIPrincipal* aPrincipal)
+{
+ RefPtr<nsAlertsIconListener> listener = mActiveListeners.Get(aAlertName);
+ if (!listener) {
+ return NS_OK;
+ }
+ mActiveListeners.Remove(aAlertName);
+ return listener->Close();
+}
+
+bool nsSystemAlertsService::IsActiveListener(const nsAString& aAlertName,
+ nsAlertsIconListener* aListener)
+{
+ return mActiveListeners.Get(aAlertName) == aListener;
+}
+
+void nsSystemAlertsService::AddListener(const nsAString& aAlertName,
+ nsAlertsIconListener* aListener)
+{
+ RefPtr<nsAlertsIconListener> oldListener = mActiveListeners.Get(aAlertName);
+ mActiveListeners.Put(aAlertName, aListener);
+ if (oldListener) {
+ // If an alert with this name already exists, close it.
+ oldListener->Close();
+ }
+}
+
+void nsSystemAlertsService::RemoveListener(const nsAString& aAlertName,
+ nsAlertsIconListener* aListener)
+{
+ if (IsActiveListener(aAlertName, aListener)) {
+ // The alert may have been replaced; only remove it from the active
+ // listeners map if it's the same.
+ mActiveListeners.Remove(aAlertName);
+ }
+}
diff --git a/toolkit/system/gnome/nsSystemAlertsService.h b/toolkit/system/gnome/nsSystemAlertsService.h
new file mode 100644
index 000000000..66ae2ea27
--- /dev/null
+++ b/toolkit/system/gnome/nsSystemAlertsService.h
@@ -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/. */
+
+#ifndef nsSystemAlertsService_h__
+#define nsSystemAlertsService_h__
+
+#include "nsIAlertsService.h"
+#include "nsDataHashtable.h"
+#include "nsCOMPtr.h"
+
+class nsAlertsIconListener;
+
+class nsSystemAlertsService : public nsIAlertsService
+{
+public:
+ NS_DECL_NSIALERTSSERVICE
+ NS_DECL_ISUPPORTS
+
+ nsSystemAlertsService();
+
+ nsresult Init();
+
+ bool IsActiveListener(const nsAString& aAlertName,
+ nsAlertsIconListener* aListener);
+ void RemoveListener(const nsAString& aAlertName,
+ nsAlertsIconListener* aListener);
+
+protected:
+ virtual ~nsSystemAlertsService();
+
+ void AddListener(const nsAString& aAlertName,
+ nsAlertsIconListener* aListener);
+
+ nsDataHashtable<nsStringHashKey, nsAlertsIconListener*> mActiveListeners;
+};
+
+#endif /* nsSystemAlertsService_h__ */