Blob Blame History Raw
From 8f05bb1332ef7ad25e599b9a7d998733564cc3c8 Mon Sep 17 00:00:00 2001
From: "Jasper St. Pierre" <jstpierre@mecheye.net>
Date: Thu, 11 Jul 2013 14:25:08 -0400
Subject: [PATCH 1/3] search: Ensure that we correctly remove remote search
 providers

When we reload the remote search providers, we currently try to remove
all remote providers, and then re-scan. It turns out that we sometimes
remove the wrong providers from the remote provider list, causing us to
have some providers not correctly unloaded.

https://bugzilla.gnome.org/show_bug.cgi?id=700283
---
 js/ui/search.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/js/ui/search.js b/js/ui/search.js
index 3dd59d7..2cc8693 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -31,7 +31,7 @@ const SearchSystem = new Lang.Class({
 
         let remoteIndex = this._remoteProviders.indexOf(provider);
         if (remoteIndex != -1)
-            this._remoteProviders.splice(index, 1);
+            this._remoteProviders.splice(remoteIndex, 1);
     },
 
     getProviders: function() {
-- 
1.9.0


From ab6694662aa79819d5140083b4eee15b312d3807 Mon Sep 17 00:00:00 2001
From: "Jasper St. Pierre" <jstpierre@mecheye.net>
Date: Fri, 26 Jul 2013 18:36:31 -0400
Subject: [PATCH 2/3] remoteSearch: Load remote search providers synchronously

As we only reload search providers on startup or when the sort order changes,
and given the small number of search providers we'll actually load, I doubt
we'll see any speed decrease.

The simplicity of synchronous code is also much clearer, and fully avoids
all the possible bugs about in-flight requests or similar.

This also prevents issues with multiple search providers showing up at once,
which happen when multiple requests to reload search providers get called
immediately, with the existing in-flight async requests never cancelled.

https://bugzilla.gnome.org/show_bug.cgi?id=700283
---
 js/ui/remoteSearch.js | 154 +++++++++++++++++++++++++-------------------------
 1 file changed, 76 insertions(+), 78 deletions(-)

diff --git a/js/ui/remoteSearch.js b/js/ui/remoteSearch.js
index e7cd6fe..323db5e 100644
--- a/js/ui/remoteSearch.js
+++ b/js/ui/remoteSearch.js
@@ -7,7 +7,6 @@ const Lang = imports.lang;
 const St = imports.gi.St;
 const Shell = imports.gi.Shell;
 
-const FileUtils = imports.misc.fileUtils;
 const Search = imports.ui.search;
 
 const KEY_FILE_GROUP = 'Shell Search Provider';
@@ -60,108 +59,107 @@ var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
 var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface);
 
 function loadRemoteSearchProviders(addProviderCallback) {
-    let data = { loadedProviders: [],
-                 objectPaths: {},
-                 addProviderCallback: addProviderCallback };
-    FileUtils.collectFromDatadirsAsync('search-providers',
-                                       { loadedCallback: remoteProvidersLoaded,
-                                         processFile: loadRemoteSearchProvider,
-                                         data: data
-                                       });
-}
-
-function loadRemoteSearchProvider(file, info, data) {
-    let keyfile = new GLib.KeyFile();
-    let path = file.get_path();
-
-    try {
-        keyfile.load_from_file(path, 0);
-    } catch(e) {
-        return;
-    }
-
-    if (!keyfile.has_group(KEY_FILE_GROUP))
-        return;
+    let objectPaths = {};
+    let loadedProviders = [];
 
-    let remoteProvider;
-    try {
-        let group = KEY_FILE_GROUP;
-        let busName = keyfile.get_string(group, 'BusName');
-        let objectPath = keyfile.get_string(group, 'ObjectPath');
+    function loadRemoteSearchProvider(file) {
+        let keyfile = new GLib.KeyFile();
+        let path = file.get_path();
 
-        if (data.objectPaths[objectPath])
-            return;
-
-        let appInfo = null;
         try {
-            let desktopId = keyfile.get_string(group, 'DesktopId');
-            appInfo = Gio.DesktopAppInfo.new(desktopId);
-        } catch (e) {
-            log('Ignoring search provider ' + path + ': missing DesktopId');
+            keyfile.load_from_file(path, 0);
+        } catch(e) {
             return;
         }
 
-        let version = '1';
+        if (!keyfile.has_group(KEY_FILE_GROUP))
+            return;
+
+        let remoteProvider;
         try {
-            version = keyfile.get_string(group, 'Version');
-        } catch (e) {
-            // ignore error
-        }
+            let group = KEY_FILE_GROUP;
+            let busName = keyfile.get_string(group, 'BusName');
+            let objectPath = keyfile.get_string(group, 'ObjectPath');
+
+            if (objectPaths[objectPath])
+                return;
+
+            let appInfo = null;
+            try {
+                let desktopId = keyfile.get_string(group, 'DesktopId');
+                appInfo = Gio.DesktopAppInfo.new(desktopId);
+            } catch (e) {
+                log('Ignoring search provider ' + path + ': missing DesktopId');
+                return;
+            }
 
-        if (version >= 2)
-            remoteProvider = new RemoteSearchProvider2(appInfo, busName, objectPath);
-        else
-            remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath);
+            let version = '1';
+            try {
+                version = keyfile.get_string(group, 'Version');
+            } catch (e) {
+                // ignore error
+            }
 
-        data.objectPaths[objectPath] = remoteProvider;
-        data.loadedProviders.push(remoteProvider);
-    } catch(e) {
-        log('Failed to add search provider %s: %s'.format(path, e.toString()));
+            if (version >= 2)
+                remoteProvider = new RemoteSearchProvider2(appInfo, busName, objectPath);
+            else
+                remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath);
+
+            objectPaths[objectPath] = remoteProvider;
+            loadedProviders.push(remoteProvider);
+        } catch(e) {
+            log('Failed to add search provider %s: %s'.format(path, e.toString()));
+        }
     }
-}
 
-function remoteProvidersLoaded(loadState) {
+    let dataDirs = GLib.get_system_data_dirs();
+    dataDirs.forEach(function(dataDir) {
+        let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']);
+        let dir = Gio.File.new_for_path(path);
+        let fileEnum = dir.enumerate_children('standard::name,standard::type',
+                                              Gio.FileQueryInfoFlags.NONE, null);
+        let info;
+        while ((info = fileEnum.next_file(null)))
+            loadRemoteSearchProvider(fileEnum.get_child(info));
+    });
+
     let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
     let sortOrder = searchSettings.get_strv('sort-order');
 
     // Special case gnome-control-center to be always active and always first
     sortOrder.unshift('gnome-control-center.desktop');
 
-    loadState.loadedProviders.sort(
-        function(providerA, providerB) {
-            let idxA, idxB;
-            let appIdA, appIdB;
+    loadedProviders.sort(function(providerA, providerB) {
+        let idxA, idxB;
+        let appIdA, appIdB;
 
-            appIdA = providerA.appInfo.get_id();
-            appIdB = providerB.appInfo.get_id();
+        appIdA = providerA.appInfo.get_id();
+        appIdB = providerB.appInfo.get_id();
 
-            idxA = sortOrder.indexOf(appIdA);
-            idxB = sortOrder.indexOf(appIdB);
+        idxA = sortOrder.indexOf(appIdA);
+        idxB = sortOrder.indexOf(appIdB);
 
-            // if no provider is found in the order, use alphabetical order
-            if ((idxA == -1) && (idxB == -1)) {
-                let nameA = providerA.appInfo.get_name();
-                let nameB = providerB.appInfo.get_name();
+        // if no provider is found in the order, use alphabetical order
+        if ((idxA == -1) && (idxB == -1)) {
+            let nameA = providerA.appInfo.get_name();
+            let nameB = providerB.appInfo.get_name();
 
-                return GLib.utf8_collate(nameA, nameB);
-            }
+            return GLib.utf8_collate(nameA, nameB);
+        }
 
-            // if providerA isn't found, it's sorted after providerB
-            if (idxA == -1)
-                return 1;
+        // if providerA isn't found, it's sorted after providerB
+        if (idxA == -1)
+            return 1;
 
-            // if providerB isn't found, it's sorted after providerA
-            if (idxB == -1)
-                return -1;
+        // if providerB isn't found, it's sorted after providerA
+        if (idxB == -1)
+            return -1;
 
-            // finally, if both providers are found, return their order in the list
-            return (idxA - idxB);
-        });
+        // finally, if both providers are found, return their order in the list
+        return (idxA - idxB);
+    });
 
-    loadState.loadedProviders.forEach(
-        function(provider) {
-            loadState.addProviderCallback(provider);
-        });
+    loadedProviders.forEach(addProviderCallback);
 }
 
 const RemoteSearchProvider = new Lang.Class({
-- 
1.9.0


From d47c0ff65deb9301458c054ffd82ac3d398a79d5 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Sat, 27 Jul 2013 10:55:57 -0400
Subject: [PATCH 3/3] search: Don't throw if provider directories don't exist

There's no /usr/local/share/gnome-shell/search-providers, so don't
throw if we don't find it.
---
 js/ui/remoteSearch.js | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/js/ui/remoteSearch.js b/js/ui/remoteSearch.js
index 323db5e..25e379c 100644
--- a/js/ui/remoteSearch.js
+++ b/js/ui/remoteSearch.js
@@ -116,11 +116,18 @@ function loadRemoteSearchProviders(addProviderCallback) {
     dataDirs.forEach(function(dataDir) {
         let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']);
         let dir = Gio.File.new_for_path(path);
-        let fileEnum = dir.enumerate_children('standard::name,standard::type',
+        let fileEnum;
+        try {
+            fileEnum = dir.enumerate_children('standard::name,standard::type',
                                               Gio.FileQueryInfoFlags.NONE, null);
-        let info;
-        while ((info = fileEnum.next_file(null)))
-            loadRemoteSearchProvider(fileEnum.get_child(info));
+        } catch (e) {
+            fileEnum = null;
+        }
+        if (fileEnum != null) {
+            let info;
+            while ((info = fileEnum.next_file(null)))
+                loadRemoteSearchProvider(fileEnum.get_child(info));
+        }
     });
 
     let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
-- 
1.9.0