changeset: 504674:5a55ac856fc4 parent: 504609:66531295716a user: Martin Stransky date: Thu Nov 21 10:32:29 2019 +0100 files: browser/components/shell/moz.build browser/components/shell/nsGNOMEShellSearchProvider.cpp browser/components/shell/nsGNOMEShellSearchProvider.h browser/components/shell/nsGNOMEShellService.cpp browser/components/shell/nsGNOMEShellService.h browser/locales/en-US/chrome/browser/browser.properties toolkit/components/remote/moz.build toolkit/components/remote/nsDBusRemoteServer.cpp description: Bug 1239694 Implemenet Gnome search provider, r?jhorak Implement org.gnome.Shell.SearchProvider2 D-Bus interface and enable it when widget.gnome-search-provider.enabled pref is set, so this feature is disabled by default. Differential Revision: https://phabricator.services.mozilla.com/D54334 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 @@ -29,16 +29,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': XPIDL_SOURCES += [ 'nsIGNOMEShellService.idl', ] SOURCES += [ 'nsGNOMEShellService.cpp', ] + if CONFIG['MOZ_ENABLE_DBUS']: + SOURCES += [ + 'nsGNOMEShellSearchProvider.cpp', + ] + elif CONFIG['OS_ARCH'] == 'WINNT': SOURCES += [ 'nsWindowsShellService.cpp', ] LOCAL_INCLUDES += [ '../../../other-licenses/nsis/Contrib/CityHash/cityhash', ] @@ -52,11 +57,13 @@ EXTRA_JS_MODULES += [ 'ScreenshotChild.jsm', 'ShellService.jsm', ] for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION'): 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.cpp b/browser/components/shell/nsGNOMEShellSearchProvider.cpp new file mode 100644 --- /dev/null +++ b/browser/components/shell/nsGNOMEShellSearchProvider.cpp @@ -0,0 +1,621 @@ +/* -*- 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(MAX_SEARCH_RESULTS_NUM); + 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::GetIDKeyForURI(int aIndex, nsAutoCString& aUri, + nsAutoCString& aIDKey) { + // Compose ID as NN:URL where NN is index to our current history + // result container. + aIDKey = nsPrintfCString("%.2d:%s", aIndex, aUri.get()); +} + +int nsGNOMEShellSearchProvider::GetIndexFromIDKey(const char* aIDKey) { + // ID is NN:URL where NN is index to our current history + // result container. + char tmp[] = {aIDKey[0], aIDKey[1], '\0'}; + return atoi(tmp); +} + +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); + + nsAutoCString idKey; + GetIDKeyForURI(i, uri, idKey); + + const char* id = idKey.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) { + nsCOMPtr child; + mHistResultContainer->GetChild(GetIndexFromIDKey(aID), 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) { + 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 { + int keyIndex = atoi(aID); + nsCOMPtr child; + mHistResultContainer->GetChild(keyIndex, getter_AddRefs(child)); + + nsAutoCString uri; + nsresult rv = child->GetUri(uri); + if (NS_FAILED(rv)) { + return; + } + + 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/nsGNOMEShellSearchProvider.h b/browser/components/shell/nsGNOMEShellSearchProvider.h new file mode 100644 --- /dev/null +++ b/browser/components/shell/nsGNOMEShellSearchProvider.h @@ -0,0 +1,55 @@ +/* -*- 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); + void GetIDKeyForURI(int aIndex, nsAutoCString& aUri, nsAutoCString& aIDKey); + int GetIndexFromIDKey(const char* aIDKey); + 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/nsGNOMEShellService.cpp b/browser/components/shell/nsGNOMEShellService.cpp --- a/browser/components/shell/nsGNOMEShellService.cpp +++ b/browser/components/shell/nsGNOMEShellService.cpp @@ -87,16 +87,24 @@ nsresult nsGNOMEShellService::Init() { // CreateInstance to succeed. nsCOMPtr giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); nsCOMPtr gsettings = do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); if (!giovfs && !gsettings) return NS_ERROR_NOT_AVAILABLE; +#ifdef MOZ_ENABLE_DBUS + const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP"); + if (currentDesktop && strstr(currentDesktop, "GNOME") != nullptr && + Preferences::GetBool("browser.gnome-search-provider.enabled", false)) { + mSearchProvider.Startup(); + } +#endif + // Check G_BROKEN_FILENAMES. If it's set, then filenames in glib use // the locale encoding. If it's not set, they use UTF-8. mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nullptr; if (GetAppPathFromLauncher()) return NS_OK; nsCOMPtr dirSvc( do_GetService("@mozilla.org/file/directory_service;1")); 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 @@ -5,16 +5,19 @@ #ifndef nsgnomeshellservice_h____ #define nsgnomeshellservice_h____ #include "nsIGNOMEShellService.h" #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 { public: nsGNOMEShellService() : mAppIsInPath(false) {} NS_DECL_ISUPPORTS NS_DECL_NSISHELLSERVICE @@ -23,15 +26,18 @@ class nsGNOMEShellService final : public nsresult Init(); private: ~nsGNOMEShellService() {} 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; bool mAppIsInPath; }; #endif // nsgnomeshellservice_h____ 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 @@ -1021,8 +1021,12 @@ confirmationHint.pinTab.label = Pinned! confirmationHint.pinTab.description = Right-click the tab to unpin it. confirmationHint.passwordSaved.label = Password saved! confirmationHint.breakageReport.label = Report sent. Thank you! # LOCALIZATION NOTE (livebookmarkMigration.title): # 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 @@ -20,16 +20,20 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk' 'RemoteUtils.cpp', ] if CONFIG['MOZ_ENABLE_DBUS']: SOURCES += [ 'nsDBusRemoteClient.cpp', 'nsDBusRemoteServer.cpp', ] CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] + EXPORTS += [ + 'nsUnixRemoteServer.h', + 'RemoteUtils.h', + ] CXXFLAGS += CONFIG['TK_CFLAGS'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': SOURCES += [ 'nsWinRemoteClient.cpp', 'nsWinRemoteServer.cpp', ] 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 @@ -22,17 +22,17 @@ #include "nsGTKToolkit.h" #include #include #include -const char* introspect_template = +static const char* introspect_template = "\n" "\n" " \n" " \n" " \n" " \n"