diff options
author | Martin Stransky <stransky@redhat.com> | 2019-11-26 12:34:14 +0100 |
---|---|---|
committer | Martin Stransky <stransky@redhat.com> | 2019-11-26 12:34:14 +0100 |
commit | 6a3819b384a33326e937e4d28f28796c57d2f1fb (patch) | |
tree | c8caf9ac6c33395f1552e8b82c248ddd7974621c /mozilla-gnome-shell-search-provider.patch | |
parent | Merge branch 'master' into f30 (diff) | |
parent | Added Gnome search provider - mzbz#1239694 (diff) | |
download | librewolf-fedora-ff-6a3819b384a33326e937e4d28f28796c57d2f1fb.tar.gz librewolf-fedora-ff-6a3819b384a33326e937e4d28f28796c57d2f1fb.tar.bz2 librewolf-fedora-ff-6a3819b384a33326e937e4d28f28796c57d2f1fb.zip |
Merge branch 'master' into f30
Diffstat (limited to 'mozilla-gnome-shell-search-provider.patch')
-rw-r--r-- | mozilla-gnome-shell-search-provider.patch | 775 |
1 files changed, 775 insertions, 0 deletions
diff --git a/mozilla-gnome-shell-search-provider.patch b/mozilla-gnome-shell-search-provider.patch new file mode 100644 index 0000000..b7e7b33 --- /dev/null +++ b/mozilla-gnome-shell-search-provider.patch @@ -0,0 +1,775 @@ +diff --git a/browser/components/shell/moz.build b/browser/components/shell/moz.build +--- a/browser/components/shell/moz.build ++++ b/browser/components/shell/moz.build +@@ -34,6 +34,11 @@ + SOURCES += [ + 'nsGNOMEShellService.cpp', + ] ++ if CONFIG['MOZ_ENABLE_DBUS']: ++ SOURCES += [ ++ 'nsGNOMEShellSearchProvider.cpp', ++ ] ++ + elif CONFIG['OS_ARCH'] == 'WINNT': + SOURCES += [ + 'nsWindowsShellService.cpp', +@@ -57,6 +62,8 @@ + DEFINES[var] = '"%s"' % CONFIG[var] + + CXXFLAGS += CONFIG['TK_CFLAGS'] ++if CONFIG['MOZ_ENABLE_DBUS']: ++ CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] + + with Files('**'): + BUG_COMPONENT = ('Firefox', 'Shell Integration') +diff --git a/browser/components/shell/nsGNOMEShellSearchProvider.h b/browser/components/shell/nsGNOMEShellSearchProvider.h +new file mode 100644 +--- /dev/null ++++ b/browser/components/shell/nsGNOMEShellSearchProvider.h +@@ -0,0 +1,53 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim:expandtab:shiftwidth=2:tabstop=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 __nsGNOMEShellSearchProvider_h__ ++#define __nsGNOMEShellSearchProvider_h__ ++ ++#include "mozilla/DBusHelpers.h" ++#include "nsINavHistoryService.h" ++#include "nsUnixRemoteServer.h" ++#include "nsCOMPtr.h" ++ ++class nsGNOMEShellSearchProvider : public nsUnixRemoteServer { ++ public: ++ nsGNOMEShellSearchProvider() : mConnection(nullptr) {} ++ ~nsGNOMEShellSearchProvider() { Shutdown(); } ++ ++ nsresult Startup(); ++ void Shutdown(); ++ ++ DBusHandlerResult HandleDBusMessage(DBusConnection* aConnection, ++ DBusMessage* msg); ++ void UnregisterDBusInterface(DBusConnection* aConnection); ++ ++ private: ++ DBusHandlerResult Introspect(DBusMessage* msg); ++ ++ DBusHandlerResult GetInitialResultSet(DBusMessage* msg); ++ DBusHandlerResult GetSubsearchResultSet(DBusMessage* msg); ++ DBusHandlerResult GetResultMetas(DBusMessage* msg); ++ DBusHandlerResult ActivateResult(DBusMessage* msg); ++ DBusHandlerResult LaunchSearch(DBusMessage* msg); ++ ++ nsresult QueryHistory(const char* aSearchTerm); ++ bool IsHistoryResultNodeURI(nsINavHistoryResultNode* aHistoryNode); ++ void AppendResultID(DBusMessageIter* aIter, const char* aID); ++ void AppendSearchID(DBusMessageIter* aIter, const char* aID); ++ void ComposeSearchResultReply(DBusMessage* aReply, const char* aSearchTerm); ++ void LaunchWithID(const char* aID, uint32_t aTimeStamp); ++ void LaunchWithAllResults(uint32_t aTimeStamp); ++ ++ // The connection is owned by DBus library ++ RefPtr<DBusConnection> mConnection; ++ nsCOMPtr<nsINavHistoryContainerResultNode> mHistResultContainer; ++ nsCOMPtr<nsINavHistoryService> mHistoryService; ++ nsAutoCStringN<32> mSearchTerm; ++ nsAutoCString mGnomeSearchTitle; ++}; ++ ++#endif // __nsGNOMEShellSearchProvider_h__ +diff --git a/browser/components/shell/nsGNOMEShellSearchProvider.cpp b/browser/components/shell/nsGNOMEShellSearchProvider.cpp +new file mode 100644 +--- /dev/null ++++ b/browser/components/shell/nsGNOMEShellSearchProvider.cpp +@@ -0,0 +1,607 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim:expandtab:shiftwidth=2:tabstop=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 "nsGNOMEShellSearchProvider.h" ++ ++#include "nsIBaseWindow.h" ++#include "nsIDocShell.h" ++#include "nsPIDOMWindow.h" ++#include "mozilla/ModuleUtils.h" ++#include "mozilla/Base64.h" ++#include "nsIServiceManager.h" ++#include "nsIWidget.h" ++#include "nsIAppShellService.h" ++#include "nsAppShellCID.h" ++#include "nsPrintfCString.h" ++#include "nsCOMPtr.h" ++#include "nsGTKToolkit.h" ++#include "nsINavHistoryService.h" ++#include "nsToolkitCompsCID.h" ++#include "nsIFaviconService.h" ++#include "RemoteUtils.h" ++#include "nsIStringBundle.h" ++ ++#include <dbus/dbus.h> ++#include <dbus/dbus-glib-lowlevel.h> ++ ++#define MAX_SEARCH_RESULTS_NUM 9 ++#define KEYWORD_SEARCH_STRING "special:search" ++#define KEYWORD_SEARCH_STRING_LEN 14 ++ ++#define DBUS_BUS_NAME "org.mozilla.Firefox.SearchProvider" ++#define DBUS_OBJECT_PATH "/org/mozilla/Firefox/SearchProvider" ++ ++static const char* introspect_template = ++ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection " ++ "1.0//EN\"\n" ++ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\";>\n" ++ "<node>\n" ++ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" ++ " <method name=\"Introspect\">\n" ++ " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n" ++ " </method>\n" ++ " </interface>\n" ++ " <interface name=\"org.gnome.Shell.SearchProvider2\">\n" ++ " <method name=\"GetInitialResultSet\">\n" ++ " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" ++ " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" ++ " </method>\n" ++ " <method name=\"GetSubsearchResultSet\">\n" ++ " <arg type=\"as\" name=\"previous_results\" direction=\"in\" />\n" ++ " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" ++ " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" ++ " </method>\n" ++ " <method name=\"GetResultMetas\">\n" ++ " <arg type=\"as\" name=\"identifiers\" direction=\"in\" />\n" ++ " <arg type=\"aa{sv}\" name=\"metas\" direction=\"out\" />\n" ++ " </method>\n" ++ " <method name=\"ActivateResult\">\n" ++ " <arg type=\"s\" name=\"identifier\" direction=\"in\" />\n" ++ " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" ++ " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" ++ " </method>\n" ++ " <method name=\"LaunchSearch\">\n" ++ " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" ++ " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" ++ " </method>\n" ++ "</interface>\n" ++ "</node>\n"; ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::Introspect(DBusMessage* aMsg) { ++ DBusMessage* reply; ++ ++ reply = dbus_message_new_method_return(aMsg); ++ if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; ++ ++ dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspect_template, ++ DBUS_TYPE_INVALID); ++ ++ dbus_connection_send(mConnection, reply, nullptr); ++ dbus_message_unref(reply); ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++nsresult nsGNOMEShellSearchProvider::QueryHistory(const char* aSearchTerm) { ++ nsresult rv; ++ nsCOMPtr<nsINavHistoryQuery> histQuery; ++ rv = mHistoryService->GetNewQuery(getter_AddRefs(histQuery)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ nsAutoCString searchTerm(aSearchTerm); ++ rv = histQuery->SetSearchTerms(NS_ConvertUTF8toUTF16(searchTerm)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ nsCOMPtr<nsINavHistoryQueryOptions> histQueryOpts; ++ rv = mHistoryService->GetNewQueryOptions(getter_AddRefs(histQueryOpts)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ // We want to get the URIs for every item in the user's history with the ++ // given host ++ rv = histQueryOpts->SetResultType(nsINavHistoryQueryOptions::RESULTS_AS_URI); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ rv = histQueryOpts->SetSortingMode( ++ nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_DESCENDING); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ rv = histQueryOpts->SetMaxResults(10); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ // We only search history, because searching both bookmarks and history ++ // is not supported, and history tends to be more comprehensive. ++ rv = histQueryOpts->SetQueryType( ++ nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ nsCOMPtr<nsINavHistoryResult> histResult; ++ rv = mHistoryService->ExecuteQuery(histQuery, histQueryOpts, ++ getter_AddRefs(histResult)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ // Delete former search results ++ mHistResultContainer = nullptr; ++ ++ rv = histResult->GetRoot(getter_AddRefs(mHistResultContainer)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ rv = mHistResultContainer->SetContainerOpen(true); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ uint32_t childCount = 0; ++ rv = mHistResultContainer->GetChildCount(&childCount); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ return childCount != 0 ? NS_OK : NS_ERROR_FAILURE; ++} ++ ++bool nsGNOMEShellSearchProvider::IsHistoryResultNodeURI( ++ nsINavHistoryResultNode* aHistoryNode) { ++ uint32_t type; ++ nsresult rv = aHistoryNode->GetType(&type); ++ if (NS_FAILED(rv) || type != nsINavHistoryResultNode::RESULT_TYPE_URI) ++ return false; ++ ++ nsAutoCString title; ++ rv = aHistoryNode->GetTitle(title); ++ if (NS_SUCCEEDED(rv) && !title.IsEmpty()) { ++ return true; ++ } ++ ++ rv = aHistoryNode->GetUri(title); ++ return NS_SUCCEEDED(rv) && !title.IsEmpty(); ++} ++ ++void nsGNOMEShellSearchProvider::ComposeSearchResultReply( ++ DBusMessage* reply, const char* aSearchTerm) { ++ uint32_t childCount = 0; ++ nsresult rv = mHistResultContainer->GetChildCount(&childCount); ++ if (NS_FAILED(rv) || childCount == 0) { ++ return; ++ } ++ ++ if (childCount > MAX_SEARCH_RESULTS_NUM) { ++ childCount = MAX_SEARCH_RESULTS_NUM; ++ } ++ ++ DBusMessageIter iter; ++ dbus_message_iter_init_append(reply, &iter); ++ DBusMessageIter iterArray; ++ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &iterArray); ++ ++ for (uint32_t i = 0; i < childCount; i++) { ++ nsCOMPtr<nsINavHistoryResultNode> child; ++ mHistResultContainer->GetChild(i, getter_AddRefs(child)); ++ if (NS_WARN_IF(NS_FAILED(rv))) { ++ continue; ++ } ++ if (!IsHistoryResultNodeURI(child)) { ++ continue; ++ } ++ ++ nsAutoCString uri; ++ child->GetUri(uri); ++ ++ nsPrintfCString idString("%d", i); ++ const char* id = idString.get(); ++ dbus_message_iter_append_basic(&iterArray, DBUS_TYPE_STRING, &id); ++ } ++ ++ nsPrintfCString searchString("%s:%s", KEYWORD_SEARCH_STRING, aSearchTerm); ++ const char* search = searchString.get(); ++ dbus_message_iter_append_basic(&iterArray, DBUS_TYPE_STRING, &search); ++ ++ dbus_message_iter_close_container(&iter, &iterArray); ++} ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::GetInitialResultSet( ++ DBusMessage* aMsg) { ++ DBusMessage* reply; ++ char** stringArray; ++ int elements; ++ ++ if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, ++ &stringArray, &elements, DBUS_TYPE_INVALID) || ++ elements == 0) { ++ reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument"); ++ } else { ++ reply = dbus_message_new_method_return(aMsg); ++ nsresult rv = QueryHistory(stringArray[0]); ++ if (NS_SUCCEEDED(rv)) { ++ ComposeSearchResultReply(reply, stringArray[0]); ++ } ++ dbus_free_string_array(stringArray); ++ } ++ ++ dbus_connection_send(mConnection, reply, nullptr); ++ dbus_message_unref(reply); ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::GetSubsearchResultSet( ++ DBusMessage* aMsg) { ++ DBusMessage* reply; ++ ++ char **unusedArray = nullptr, **stringArray = nullptr; ++ int unusedNum, elements; ++ ++ if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, ++ &unusedArray, &unusedNum, DBUS_TYPE_ARRAY, ++ DBUS_TYPE_STRING, &stringArray, &elements, ++ DBUS_TYPE_INVALID) || ++ elements == 0) { ++ reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument"); ++ } else { ++ reply = dbus_message_new_method_return(aMsg); ++ nsresult rv = QueryHistory(stringArray[0]); ++ if (NS_SUCCEEDED(rv)) { ++ ComposeSearchResultReply(reply, stringArray[0]); ++ } ++ } ++ ++ if (unusedArray) { ++ dbus_free_string_array(unusedArray); ++ } ++ if (stringArray) { ++ dbus_free_string_array(stringArray); ++ } ++ ++ dbus_connection_send(mConnection, reply, nullptr); ++ dbus_message_unref(reply); ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++static void appendStringDictionary(DBusMessageIter* aIter, const char* aKey, ++ const char* aValue) { ++ DBusMessageIter iterDict, iterVar; ++ dbus_message_iter_open_container(aIter, DBUS_TYPE_DICT_ENTRY, nullptr, ++ &iterDict); ++ dbus_message_iter_append_basic(&iterDict, DBUS_TYPE_STRING, &aKey); ++ dbus_message_iter_open_container(&iterDict, DBUS_TYPE_VARIANT, "s", &iterVar); ++ dbus_message_iter_append_basic(&iterVar, DBUS_TYPE_STRING, &aValue); ++ dbus_message_iter_close_container(&iterDict, &iterVar); ++ dbus_message_iter_close_container(aIter, &iterDict); ++} ++ ++/* We can return those fields at GetResultMetas: ++ "id": the result ID ++ "name": the display name for the result ++ "icon": a serialized GIcon (see g_icon_serialize()), or alternatively, ++ "gicon": a textual representation of a GIcon (see g_icon_to_string()), ++ or alternativly, ++ "icon-data": a tuple of type (iiibiiay) describing a pixbuf with width, ++ height, rowstride, has-alpha, bits-per-sample, and image data ++ "description": an optional short description (1-2 lines) ++*/ ++void nsGNOMEShellSearchProvider::AppendResultID(DBusMessageIter* aIter, ++ const char* aID) { ++ int keyIndex = atoi(aID); ++ nsCOMPtr<nsINavHistoryResultNode> child; ++ mHistResultContainer->GetChild(keyIndex, getter_AddRefs(child)); ++ ++ nsAutoCString title; ++ if (NS_FAILED(child->GetTitle(title))) { ++ return; ++ } ++ ++ if (title.IsEmpty()) { ++ if (NS_FAILED(child->GetUri(title)) || title.IsEmpty()) { ++ return; ++ } ++ } ++ ++ const char* titleStr = title.get(); ++ appendStringDictionary(aIter, "id", aID); ++ appendStringDictionary(aIter, "name", titleStr); ++ appendStringDictionary(aIter, "gicon", "text-html"); ++} ++ ++void nsGNOMEShellSearchProvider::AppendSearchID(DBusMessageIter* aIter, ++ const char* aID) { ++ if (strlen(aID) < KEYWORD_SEARCH_STRING_LEN + 2) { ++ return; ++ } ++ appendStringDictionary(aIter, "id", KEYWORD_SEARCH_STRING); ++ mSearchTerm = nsAutoCStringN<32>(aID + KEYWORD_SEARCH_STRING_LEN + 1); ++ nsPrintfCString searchString(mGnomeSearchTitle.get(), mSearchTerm.get()); ++ appendStringDictionary(aIter, "name", searchString.get()); ++ appendStringDictionary(aIter, "gicon", "org.mozilla.Firefox"); ++} ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::GetResultMetas( ++ DBusMessage* aMsg) { ++ DBusMessage* reply; ++ char** stringArray; ++ int elements; ++ ++ if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, ++ &stringArray, &elements, DBUS_TYPE_INVALID) || ++ elements == 0) { ++ reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument"); ++ } else { ++ reply = dbus_message_new_method_return(aMsg); ++ ++ DBusMessageIter iter; ++ dbus_message_iter_init_append(reply, &iter); ++ DBusMessageIter iterArray; ++ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", ++ &iterArray); ++ ++ DBusMessageIter iterArray2; ++ for (int i = 0; i < elements; i++) { ++ dbus_message_iter_open_container(&iterArray, DBUS_TYPE_ARRAY, "{sv}", ++ &iterArray2); ++ if (strncmp(stringArray[i], KEYWORD_SEARCH_STRING, ++ KEYWORD_SEARCH_STRING_LEN) == 0) { ++ AppendSearchID(&iterArray2, stringArray[i]); ++ } else { ++ AppendResultID(&iterArray2, stringArray[i]); ++ } ++ dbus_message_iter_close_container(&iterArray, &iterArray2); ++ } ++ ++ dbus_message_iter_close_container(&iter, &iterArray); ++ dbus_free_string_array(stringArray); ++ } ++ ++ dbus_connection_send(mConnection, reply, nullptr); ++ dbus_message_unref(reply); ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++void nsGNOMEShellSearchProvider::LaunchWithID(const char* aID, ++ uint32_t aTimeStamp) { ++ int keyIndex = atoi(aID); ++ nsCOMPtr<nsINavHistoryResultNode> child; ++ mHistResultContainer->GetChild(keyIndex, getter_AddRefs(child)); ++ ++ nsAutoCString uri; ++ nsresult rv = child->GetUri(uri); ++ if (NS_FAILED(rv)) { ++ return; ++ } ++ ++ char* commandLine = nullptr; ++ int tmp; ++ ++ if (strncmp(aID, KEYWORD_SEARCH_STRING, KEYWORD_SEARCH_STRING_LEN) == 0) { ++ nsPrintfCString searchString("search:%s", mSearchTerm.get()); ++ const char* urlList[2] = {"unused", searchString.get()}; ++ commandLine = ConstructCommandLine(2, (char**)urlList, 0, &tmp); ++ } else { ++ const char* urlList[2] = {"unused", uri.get()}; ++ commandLine = ConstructCommandLine(2, (char**)urlList, 0, &tmp); ++ } ++ ++ if (commandLine) { ++ HandleCommandLine(commandLine, aTimeStamp); ++ free(commandLine); ++ } ++} ++ ++void nsGNOMEShellSearchProvider::LaunchWithAllResults(uint32_t aTimeStamp) { ++ uint32_t childCount = 0; ++ nsresult rv = mHistResultContainer->GetChildCount(&childCount); ++ if (NS_FAILED(rv) || childCount == 0) { ++ return; ++ } ++ ++ if (childCount > MAX_SEARCH_RESULTS_NUM) { ++ childCount = MAX_SEARCH_RESULTS_NUM; ++ } ++ ++ char** urlList = (char**)moz_xmalloc(sizeof(char*) * (childCount + 2)); ++ int urlListElements = 0; ++ ++ urlList[urlListElements++] = strdup("unused"); ++ ++ for (uint32_t i = 0; i < childCount; i++) { ++ nsCOMPtr<nsINavHistoryResultNode> child; ++ mHistResultContainer->GetChild(i, getter_AddRefs(child)); ++ ++ if (!IsHistoryResultNodeURI(child)) { ++ continue; ++ } ++ ++ nsAutoCString uri; ++ nsresult rv = child->GetUri(uri); ++ if (NS_FAILED(rv)) { ++ continue; ++ } ++ urlList[urlListElements++] = strdup(uri.get()); ++ } ++ ++ nsPrintfCString searchString("search:%s", mSearchTerm.get()); ++ urlList[urlListElements++] = strdup(searchString.get()); ++ ++ int tmp; ++ char* commandLine = ConstructCommandLine(urlListElements, urlList, 0, &tmp); ++ if (commandLine) { ++ HandleCommandLine(commandLine, aTimeStamp); ++ free(commandLine); ++ } ++ ++ for (int i = 0; i < urlListElements; i++) { ++ free(urlList[i]); ++ } ++ free(urlList); ++} ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::ActivateResult( ++ DBusMessage* aMsg) { ++ DBusMessage* reply; ++ char* resultID; ++ char** stringArray; ++ int elements; ++ uint32_t timestamp; ++ ++ if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_STRING, &resultID, ++ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &stringArray, ++ &elements, DBUS_TYPE_UINT32, ×tamp, ++ DBUS_TYPE_INVALID) || ++ resultID == nullptr) { ++ reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument"); ++ } else { ++ reply = dbus_message_new_method_return(aMsg); ++ LaunchWithID(resultID, timestamp); ++ dbus_free_string_array(stringArray); ++ } ++ ++ dbus_connection_send(mConnection, reply, nullptr); ++ dbus_message_unref(reply); ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::LaunchSearch(DBusMessage* aMsg) { ++ DBusMessage* reply; ++ char** stringArray; ++ int elements; ++ uint32_t timestamp; ++ ++ if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, ++ &stringArray, &elements, DBUS_TYPE_UINT32, ++ ×tamp, DBUS_TYPE_INVALID) || ++ elements == 0) { ++ reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument"); ++ } else { ++ reply = dbus_message_new_method_return(aMsg); ++ LaunchWithAllResults(timestamp); ++ dbus_free_string_array(stringArray); ++ } ++ ++ dbus_connection_send(mConnection, reply, nullptr); ++ dbus_message_unref(reply); ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++} ++ ++DBusHandlerResult nsGNOMEShellSearchProvider::HandleDBusMessage( ++ DBusConnection* aConnection, DBusMessage* aMsg) { ++ NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection."); ++ ++ const char* method = dbus_message_get_member(aMsg); ++ const char* iface = dbus_message_get_interface(aMsg); ++ ++ if ((strcmp("Introspect", method) == 0) && ++ (strcmp("org.freedesktop.DBus.Introspectable", iface) == 0)) { ++ return Introspect(aMsg); ++ } ++ ++ if (strcmp("org.gnome.Shell.SearchProvider2", iface) == 0) { ++ if (strcmp("GetInitialResultSet", method) == 0) { ++ return GetInitialResultSet(aMsg); ++ } ++ if (strcmp("GetSubsearchResultSet", method) == 0) { ++ return GetSubsearchResultSet(aMsg); ++ } ++ if (strcmp("GetResultMetas", method) == 0) { ++ return GetResultMetas(aMsg); ++ } ++ if (strcmp("ActivateResult", method) == 0) { ++ return ActivateResult(aMsg); ++ } ++ if (strcmp("LaunchSearch", method) == 0) { ++ return LaunchSearch(aMsg); ++ } ++ } ++ ++ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; ++} ++ ++void nsGNOMEShellSearchProvider::UnregisterDBusInterface( ++ DBusConnection* aConnection) { ++ NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection."); ++ // Not implemented ++} ++ ++static DBusHandlerResult message_handler(DBusConnection* conn, ++ DBusMessage* aMsg, void* user_data) { ++ auto interface = static_cast<nsGNOMEShellSearchProvider*>(user_data); ++ return interface->HandleDBusMessage(conn, aMsg); ++} ++ ++static void unregister(DBusConnection* conn, void* user_data) { ++ auto interface = static_cast<nsGNOMEShellSearchProvider*>(user_data); ++ interface->UnregisterDBusInterface(conn); ++} ++ ++static DBusObjectPathVTable remoteHandlersTable = { ++ .unregister_function = unregister, ++ .message_function = message_handler, ++}; ++ ++nsresult nsGNOMEShellSearchProvider::Startup() { ++ if (mConnection && dbus_connection_get_is_connected(mConnection)) { ++ // We're already connected so we don't need to reconnect ++ return NS_ERROR_ALREADY_INITIALIZED; ++ } ++ ++ nsCOMPtr<nsIStringBundleService> sbs = ++ do_GetService(NS_STRINGBUNDLE_CONTRACTID); ++ if (NS_WARN_IF(!sbs)) { ++ return NS_ERROR_FAILURE; ++ } ++ ++ nsCOMPtr<nsIStringBundle> bundle; ++ sbs->CreateBundle("chrome://browser/locale/browser.properties", ++ getter_AddRefs(bundle)); ++ if (NS_WARN_IF(!bundle)) { ++ return NS_ERROR_FAILURE; ++ } ++ ++ nsAutoString searchTitle; ++ bundle->GetStringFromName("gnomeSearchProviderSearch", searchTitle); ++ mGnomeSearchTitle = NS_ConvertUTF16toUTF8(searchTitle); ++ ++ mHistoryService = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID); ++ if (!mHistoryService) { ++ return NS_ERROR_FAILURE; ++ } ++ ++ mConnection = ++ already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SESSION, nullptr)); ++ if (!mConnection) { ++ return NS_ERROR_FAILURE; ++ } ++ dbus_connection_set_exit_on_disconnect(mConnection, false); ++ dbus_connection_setup_with_g_main(mConnection, nullptr); ++ ++ DBusError err; ++ dbus_error_init(&err); ++ dbus_bus_request_name(mConnection, DBUS_BUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, ++ &err); ++ // The interface is already owned - there is another application/profile ++ // instance already running. ++ if (dbus_error_is_set(&err)) { ++ dbus_error_free(&err); ++ mConnection = nullptr; ++ return NS_ERROR_FAILURE; ++ } ++ ++ if (!dbus_connection_register_object_path(mConnection, DBUS_OBJECT_PATH, ++ &remoteHandlersTable, this)) { ++ mConnection = nullptr; ++ return NS_ERROR_FAILURE; ++ } ++ ++ return NS_OK; ++} ++ ++void nsGNOMEShellSearchProvider::Shutdown() { ++ if (!mConnection) { ++ return; ++ } ++ ++ dbus_connection_unregister_object_path(mConnection, DBUS_OBJECT_PATH); ++ ++ // dbus_connection_unref() will be called by RefPtr here. ++ mConnection = nullptr; ++} +diff --git a/browser/components/shell/nsGNOMEShellService.h b/browser/components/shell/nsGNOMEShellService.h +--- a/browser/components/shell/nsGNOMEShellService.h ++++ b/browser/components/shell/nsGNOMEShellService.h +@@ -10,6 +10,9 @@ + #include "nsToolkitShellService.h" + #include "nsString.h" + #include "mozilla/Attributes.h" ++#ifdef MOZ_ENABLE_DBUS ++# include "nsGNOMEShellSearchProvider.h" ++#endif + + class nsGNOMEShellService final : public nsIGNOMEShellService, + public nsToolkitShellService { +@@ -28,6 +31,9 @@ + bool KeyMatchesAppName(const char* aKeyValue) const; + bool CheckHandlerMatchesAppName(const nsACString& handler) const; + ++#ifdef MOZ_ENABLE_DBUS ++ nsGNOMEShellSearchProvider mSearchProvider; ++#endif + bool GetAppPathFromLauncher(); + bool mUseLocaleFilenames; + nsCString mAppPath; +diff --git a/browser/components/shell/nsGNOMEShellService.cpp b/browser/components/shell/nsGNOMEShellService.cpp +--- a/browser/components/shell/nsGNOMEShellService.cpp ++++ b/browser/components/shell/nsGNOMEShellService.cpp +@@ -107,7 +107,15 @@ + getter_AddRefs(appPath)); + NS_ENSURE_SUCCESS(rv, rv); + +- return appPath->GetNativePath(mAppPath); ++ rv = appPath->GetNativePath(mAppPath); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++#ifdef MOZ_ENABLE_DBUS ++ if (Preferences::GetBool("widget.gnome-search-provider.enabled", false)) { ++ mSearchProvider.Startup(); ++ } ++#endif ++ return NS_OK; + } + + NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService, +diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties +--- a/browser/locales/en-US/chrome/browser/browser.properties ++++ b/browser/locales/en-US/chrome/browser/browser.properties +@@ -1026,3 +1026,7 @@ + # Used by the export of user's live bookmarks to an OPML file as a title for the file. + # %S will be replaced with brandShortName + livebookmarkMigration.title = %S Live Bookmarks ++ ++# LOCALIZATION NOTE (gnomeSearchProviderSearch): ++# Used for search by Gnome Shell activity screen, %s is a searched string. ++gnomeSearchProviderSearch=Search the web for ā%sā +diff --git a/toolkit/components/remote/moz.build b/toolkit/components/remote/moz.build +--- a/toolkit/components/remote/moz.build ++++ b/toolkit/components/remote/moz.build +@@ -25,6 +25,10 @@ + 'nsDBusRemoteServer.cpp', + ] + CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] ++ EXPORTS += [ ++ 'nsUnixRemoteServer.h', ++ 'RemoteUtils.h', ++ ] + CXXFLAGS += CONFIG['TK_CFLAGS'] + + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': +diff --git a/toolkit/components/remote/nsDBusRemoteServer.cpp b/toolkit/components/remote/nsDBusRemoteServer.cpp +--- a/toolkit/components/remote/nsDBusRemoteServer.cpp ++++ b/toolkit/components/remote/nsDBusRemoteServer.cpp +@@ -27,7 +27,7 @@ + + #include <dlfcn.h> + +-const char* introspect_template = ++static const char* introspect_template = + "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection " + "1.0//EN\"\n" + "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\";>\n" + |