search: Add RemoteSearchProvider
Add an asynchronous search provider for results from a DBus service implementing the org.gnome.Shell.SearchProvider interface; this will allow applications to hook into the Shell's search without implementing it in Shell itself or requiring an extension. https://bugzilla.gnome.org/show_bug.cgi?id=663125
This commit is contained in:
parent
89fe43f70c
commit
f6749fb204
@ -17,6 +17,9 @@ dist_searchproviders_DATA = \
|
|||||||
open-search-providers/google.xml \
|
open-search-providers/google.xml \
|
||||||
open-search-providers/wikipedia.xml
|
open-search-providers/wikipedia.xml
|
||||||
|
|
||||||
|
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||||
|
introspection_DATA = org.gnome.ShellSearchProvider.xml
|
||||||
|
|
||||||
themedir = $(pkgdatadir)/theme
|
themedir = $(pkgdatadir)/theme
|
||||||
dist_theme_DATA = \
|
dist_theme_DATA = \
|
||||||
theme/calendar-arrow-left.svg \
|
theme/calendar-arrow-left.svg \
|
||||||
@ -73,6 +76,7 @@ shaders_DATA = \
|
|||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
gnome-shell.desktop.in.in \
|
gnome-shell.desktop.in.in \
|
||||||
gnome-shell-extension-prefs.desktop.in.in \
|
gnome-shell-extension-prefs.desktop.in.in \
|
||||||
|
$(introspection_DATA) \
|
||||||
$(menu_DATA) \
|
$(menu_DATA) \
|
||||||
$(shaders_DATA) \
|
$(shaders_DATA) \
|
||||||
$(convert_DATA) \
|
$(convert_DATA) \
|
||||||
|
147
data/org.gnome.ShellSearchProvider.xml
Normal file
147
data/org.gnome.ShellSearchProvider.xml
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<!DOCTYPE node PUBLIC
|
||||||
|
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||||
|
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||||
|
<node>
|
||||||
|
<interface name="org.gnome.Shell.SearchProvider">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
The interface used for integrating into GNOME Shell's search
|
||||||
|
interface.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
|
||||||
|
<method name="GetInitialResultSet">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Called when the user first begins a search.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
Array of search terms, which the provider should treat as
|
||||||
|
logical AND.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" direction="out">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
An array of result identifier strings representing items which
|
||||||
|
match the given search terms. Identifiers must be unique within
|
||||||
|
the provider's domain, but other than that may be chosen freely
|
||||||
|
by the provider.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="GetSubsearchResultSet">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Called when a search is performed which is a "subsearch" of
|
||||||
|
the previous search, e.g. the method may return less results, but
|
||||||
|
not more or different results.
|
||||||
|
|
||||||
|
This allows search providers to only search through the previous
|
||||||
|
result set, rather than possibly performing a full re-query.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
Array of item identifiers
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
Array of updated search terms, which the provider should treat as
|
||||||
|
logical AND.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" direction="out">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
An array of result identifier strings representing items which
|
||||||
|
match the given search terms. Identifiers must be unique within
|
||||||
|
the provider's domain, but other than that may be chosen freely
|
||||||
|
by the provider.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="GetResultMetas">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Return an array of meta data used to display each given result
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
An array of result identifiers as returned by
|
||||||
|
GetInitialResultSet() or GetSubsearchResultSet()
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="a{sv}" direction="out">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
A dictionary describing the given search result, containing
|
||||||
|
'id', 'name' (both strings) and either 'icon' (a serialized
|
||||||
|
GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
|
||||||
|
height, rowstride, has-alpha, bits per sample, channels, data)
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="ActivateResult">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Called when the users chooses a given result. The result should
|
||||||
|
be displayed in the application associated with the corresponding
|
||||||
|
provider.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="s" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
A result identifier as returned by GetInitialResultSet() or
|
||||||
|
GetSubsearchResultSet()
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
@ -75,6 +75,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/placeDisplay.js \
|
ui/placeDisplay.js \
|
||||||
ui/polkitAuthenticationAgent.js \
|
ui/polkitAuthenticationAgent.js \
|
||||||
ui/popupMenu.js \
|
ui/popupMenu.js \
|
||||||
|
ui/remoteSearch.js \
|
||||||
ui/runDialog.js \
|
ui/runDialog.js \
|
||||||
ui/scripting.js \
|
ui/scripting.js \
|
||||||
ui/search.js \
|
ui/search.js \
|
||||||
|
131
js/ui/remoteSearch.js
Normal file
131
js/ui/remoteSearch.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
|
const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
|
||||||
|
<method name="GetInitialResultSet">
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="as" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="GetSubsearchResultSet">
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="as" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="GetResultMetas">
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="aa{sv}" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="ActivateResult">
|
||||||
|
<arg type="s" direction="in" />
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
||||||
|
|
||||||
|
|
||||||
|
const RemoteSearchProvider = new Lang.Class({
|
||||||
|
Name: 'RemoteSearchProvider',
|
||||||
|
Extends: Search.SearchProvider,
|
||||||
|
|
||||||
|
_init: function(title, icon, dbusName, dbusPath) {
|
||||||
|
this._proxy = new SearchProviderProxy(Gio.DBus.session,
|
||||||
|
dbusName, dbusPath);
|
||||||
|
|
||||||
|
this.parent(title.toUpperCase());
|
||||||
|
this.async = true;
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon: function(size, meta) {
|
||||||
|
if (meta['gicon']) {
|
||||||
|
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
||||||
|
icon_size: size,
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
|
} else if (meta['icon-data']) {
|
||||||
|
let [width, height, rowStride, hasAlpha,
|
||||||
|
bitsPerSample, nChannels, data] = meta['icon-data'];
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
|
return textureCache.load_from_raw(data, hasAlpha,
|
||||||
|
width, height, rowStride, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ugh, but we want to fall back to something ...
|
||||||
|
return new St.Icon({ icon_name: 'text-x-generic',
|
||||||
|
icon_size: size,
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
|
},
|
||||||
|
|
||||||
|
_getResultsFinished: function(results, error) {
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
|
this.searchSystem.pushResults(this, results[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialResultSetAsync: function(terms) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
try {
|
||||||
|
this._proxy.GetInitialResultSetRemote(terms,
|
||||||
|
Lang.bind(this, this._getResultsFinished),
|
||||||
|
this._cancellable);
|
||||||
|
} catch(e) {
|
||||||
|
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
|
||||||
|
this.searchSystem.pushResults(this, []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubsearchResultSetAsync: function(previousResults, newTerms) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
try {
|
||||||
|
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
||||||
|
Lang.bind(this, this._getResultsFinished),
|
||||||
|
this._cancellable);
|
||||||
|
} catch(e) {
|
||||||
|
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
|
||||||
|
this.searchSystem.pushResults(this, []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getResultMetasFinished: function(results, error, callback) {
|
||||||
|
if (error) {
|
||||||
|
callback([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let metas = results[0];
|
||||||
|
let resultMetas = [];
|
||||||
|
for (let i = 0; i < metas.length; i++) {
|
||||||
|
for (let prop in metas[i])
|
||||||
|
metas[i][prop] = metas[i][prop].deep_unpack();
|
||||||
|
resultMetas.push({ id: metas[i]['id'],
|
||||||
|
name: metas[i]['name'],
|
||||||
|
createIcon: Lang.bind(this,
|
||||||
|
this.createIcon, metas[i]) });
|
||||||
|
}
|
||||||
|
callback(resultMetas);
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultMetasAsync: function(ids, callback) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
try {
|
||||||
|
this._proxy.GetResultMetasRemote(ids,
|
||||||
|
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||||
|
this._cancellable);
|
||||||
|
} catch(e) {
|
||||||
|
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
|
||||||
|
callback([]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(id) {
|
||||||
|
this._proxy.ActivateResultRemote(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user