From 8b1630cbac9ef4b5c4ea3b4362559200ca718067 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Tue, 26 Nov 2019 12:33:52 +0100 Subject: [PATCH] Added Gnome search provider - mzbz#1239694 --- firefox-search-provider.ini | 5 + firefox.metainfo.appdata.xml | 68 ++ firefox.spec | 13 + mozilla-gnome-shell-search-provider.patch | 775 ++++++++++++++++++++++ 4 files changed, 861 insertions(+) create mode 100644 firefox-search-provider.ini create mode 100644 firefox.metainfo.appdata.xml create mode 100644 mozilla-gnome-shell-search-provider.patch diff --git a/firefox-search-provider.ini b/firefox-search-provider.ini new file mode 100644 index 0000000..22fc763 --- /dev/null +++ b/firefox-search-provider.ini @@ -0,0 +1,5 @@ +[Shell Search Provider] +DesktopId=org.mozilla.Firefox.desktop +BusName=org.mozilla.Firefox.SearchProvider +ObjectPath=/org/mozilla/Firefox/SearchProvider +Version=2 diff --git a/firefox.metainfo.appdata.xml b/firefox.metainfo.appdata.xml new file mode 100644 index 0000000..b6d8050 --- /dev/null +++ b/firefox.metainfo.appdata.xml @@ -0,0 +1,68 @@ + + + + org.mozilla.Firefox.desktop + CC0-1.0 + Firefox + Web Browser + =Navegador web + =Webový prohlížeč + =Navegador web + =مرورگر اینترنتی + =WWW-selain + =Navigateur Web + =Webböngésző + =Browser Web + =ウェブ・ブラウザ + =웹 브라우저 + =Nettleser + =Webbrowser + =Nettlesar + =Nettleser + =Przeglądarka WWW + =Navegador Web + =Navegador Web + =Internetový prehliadač + =Webbläsare + +

Browse the Web

+

Navegueu per el web

+

Prohlížení stránek World Wide Webu

+

Im Internet surfen

+

Navegue por la web

+

صفحات شبکه جهانی اینترنت را مرور نمایید

+

Selaa Internetin WWW-sivuja

+

Navigue sur Internet

+

A világháló böngészése

+

Esplora il web

+

ウェブを閲覧します

+

웹을 돌아 다닙니다

+

Surf på nettet

+

Verken het internet

+

Surf på nettet

+

Surf på nettet

+

Przeglądanie stron WWW

+

Navegue na Internet

+

Navegue na Internet

+

Prehliadanie internetu

+

Surfa på webben

+
+ https://www.mozilla.org + stransky@redhat.com + + ModernToolkit + SearchProvider + + Mozilla + GPL-3.0+ + Mozilla Corporation + https://bugzilla.mozilla.org/ + https://support.mozilla.org/ + firefox + + firefox.desktop + + + + +
diff --git a/firefox.spec b/firefox.spec index 77c9a75..84aa522 100644 --- a/firefox.spec +++ b/firefox.spec @@ -116,6 +116,8 @@ Source29: firefox-wayland.desktop Source30: firefox-x11.sh.in Source31: firefox-x11.desktop Source32: node-stdout-nonblocking-wrapper +Source33: firefox.metainfo.appdata.xml +Source34: firefox-search-provider.ini # Build patches Patch3: mozilla-build-arm.patch @@ -143,6 +145,7 @@ Patch224: mozilla-1170092.patch Patch226: rhbz-1354671.patch Patch227: firefox-locale-debug.patch Patch228: mozilla-1583466.patch +Patch239: mozilla-gnome-shell-search-provider.patch # Upstream patches Patch402: mozilla-1196777.patch @@ -353,6 +356,8 @@ This package contains results of tests executed during build. %endif %patch227 -p1 -b .locale-debug %patch228 -p1 -b .mozilla-1583466 +%patch239 -p1 -b .gnome-shell-search-provider + %patch402 -p1 -b .1196777 %ifarch %{arm} %patch415 -p1 -b .1238661 @@ -836,6 +841,12 @@ sed -i -e "s/\[Crash Reporter\]/[Crash Reporter]\nEnabled=1/" %{buildroot}/%{moz %{__mkdir_p} %{buildroot}%{mozappdir}/distribution %{__cp} %{SOURCE26} %{buildroot}%{mozappdir}/distribution +# Install Gnome search provider files +mkdir -p %{buildroot}%{_datadir}/metainfo +%{__cp} %{SOURCE33} %{buildroot}%{_datadir}/metainfo +mkdir -p %{buildroot}%{_datadir}/gnome-shell/search-providers +%{__cp} %{SOURCE34} %{buildroot}%{_datadir}/gnome-shell/search-providers + # Remove copied libraries to speed up build rm -f %{buildroot}%{mozappdirdev}/sdk/lib/libmozjs.so rm -f %{buildroot}%{mozappdirdev}/sdk/lib/libmozalloc.so @@ -896,6 +907,8 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %dir %{_libdir}/mozilla/extensions/* %{_datadir}/appdata/*.appdata.xml %{_datadir}/applications/%{name}.desktop +%{_datadir}/metainfo/*.appdata.xml +%{_datadir}/gnome-shell/search-providers/*.ini %dir %{mozappdir} %license %{mozappdir}/LICENSE %{mozappdir}/browser/chrome 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 mConnection; ++ nsCOMPtr mHistResultContainer; ++ nsCOMPtr 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 ++#include ++ ++#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 = ++ "\n" ++ "\n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" ++ "\n" ++ "\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 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 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 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 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 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 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 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(user_data); ++ return interface->HandleDBusMessage(conn, aMsg); ++} ++ ++static void unregister(DBusConnection* conn, void* user_data) { ++ auto interface = static_cast(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 sbs = ++ do_GetService(NS_STRINGBUNDLE_CONTRACTID); ++ if (NS_WARN_IF(!sbs)) { ++ return NS_ERROR_FAILURE; ++ } ++ ++ nsCOMPtr 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(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 + +-const char* introspect_template = ++static const char* introspect_template = + "\n" +