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/wikipedia.xml
|
||||
|
||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||
introspection_DATA = org.gnome.ShellSearchProvider.xml
|
||||
|
||||
themedir = $(pkgdatadir)/theme
|
||||
dist_theme_DATA = \
|
||||
theme/calendar-arrow-left.svg \
|
||||
@ -73,6 +76,7 @@ shaders_DATA = \
|
||||
EXTRA_DIST = \
|
||||
gnome-shell.desktop.in.in \
|
||||
gnome-shell-extension-prefs.desktop.in.in \
|
||||
$(introspection_DATA) \
|
||||
$(menu_DATA) \
|
||||
$(shaders_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/polkitAuthenticationAgent.js \
|
||||
ui/popupMenu.js \
|
||||
ui/remoteSearch.js \
|
||||
ui/runDialog.js \
|
||||
ui/scripting.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