Below is javascript code for a gnome shell 3.4 extension that will add remmina configurations that are stored in a text file to the shell search results. I plan to update this extension in the future to read the contents .remmina directory instead of a text file. The text file is assumed to be ~/src/rdp and contain an rdp per line in the format: Server 1{tab}12312323.remmina Server 2{tab}23444324.remmina etc.
const St = imports.gi.St; const Main = imports.ui.main; const Search = imports.ui.search; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const Lang = imports.lang; const Shell = imports.gi.Shell; const Util = imports.misc.util; // define search provider object var rdpSearchProvider = null; // define file watch to detect changes in the source text file var rdpConfigFileWatcher = null; // define class const RemminaSearchProvider = new Lang.Class({ Name: 'RemminaSearchProvider', Extends: Search.SearchProvider, // init _init: function(name) { global.log('init remmina-search'); Search.SearchProvider.prototype._init.call(this, "Remote Desktops"); // define remmina path this.remminaPath = GLib.build_filenamev([GLib.get_home_dir(), ".remmina"]); // define config path for remmina definitions this.remminaConfigPath = GLib.build_filenamev([GLib.get_home_dir(), "src/rdp"]); // define the remmina config list and read this._remminaConfigs = []; this._readRemminaConfigs(); // setup file monitor to detect changes let fileWatch = Gio.file_new_for_path(this.remminaConfigPath); rdpConfigFileWatcher = fileWatch.monitor(Gio.FileMonitorFlags.NONE, null); rdpConfigFileWatcher.connect('changed', Lang.bind(this, this._readRemminaConfigs)); return true; }, // function that reads the configurations from the file _readRemminaConfigs : function () { // init list this._remminaConfigs = []; // get the file data let filedata; try { filedata = GLib.file_get_contents(this.remminaConfigPath, null, 0); } catch (e) { Main.notifyError("Error reading file", e.message); return false; } // attempt to parse the data if ( (filedata[1].length != 0) && (filedata[1] != null) ) { try { // get each line let rdpInfoLines = String(filedata[1]).trim().split('\n'); for (var i=0; i<rdpInfoLines.length; i++) { // parse rdp info: 0 = name, 1 = remmina config file let rdpInfo = String(rdpInfoLines[i]).trim().split('\t'); // push rdp info to the list this._remminaConfigs.push([rdpInfo[0], this.remminaPath + "/" + rdpInfo[1]]); } } catch (e) { Main.notifyError("Error parsing file - "+ filedata, e.message); return false; } } else { Main.notifyError("Error parsing file - Empty data"); return false; } // ok return true; }, // return results back to search getResultMetas: function(resultIds, callback) { // define results let metas = []; // go through each result for (let i = 0; i < resultIds.length; i++) { let resultId = resultIds[i]; // get the rdp name, fallback to url if no name let rdpInfoName = ""; if (resultId.name) rdpInfoName = resultId.name; else rdpInfoName = resultId.url; // add the result to the list metas.push({ 'id': resultId, 'name': rdpInfoName, 'createIcon': function(size) { let xicon = new Gio.ThemedIcon({name: 'remmina'}); return new St.Icon({icon_size: size, gicon: xicon}); } }); } // call back with results callback(metas); }, // define method to open fetched result activateResult: function(id) { Util.spawn(['/usr/bin/remmina', '-c', id.url]); }, // function that searches the rdp configs using terms passed _checkRemminaConfigs: function(configs, terms) { // define results let searchResults = []; // go through each rdp and term for (var i=0; i<configs.length; i++) { for (var j=0; j<terms.length; j++) { try { // get the name and url and build the string to search let name = configs[i][0]; let url = configs[i][1]; let searchStr = name+url; // search the string let pattern = new RegExp(terms[j],"gi"); if (searchStr.match(pattern)) { // add to the list if matched searchResults.push({ 'name': name, 'url': url }); } } catch(ex) { continue; } } } // return results return searchResults; }, // function that returns the initial results getInitialResultSet: function(terms) { this.searchSystem.pushResults(this, this._checkRemminaConfigs(this._remminaConfigs, terms)); }, // call same initial search on subsearch getSubsearchResultSet: function(previousResults, terms) { this.getInitialResultSet(terms); } }); // init event function init(meta) { } // enable event function enable() { // check if search provider already initialized, create new if (rdpSearchProvider==null) { rdpSearchProvider = new RemminaSearchProvider(); Main.overview.addSearchProvider(rdpSearchProvider); } } // disable event function disable() { // if search provider exists, disable it if (rdpSearchProvider!=null) { Main.overview.removeSearchProvider(rdpSearchProvider); rdpSearchProvider.rdpConfigFileWatcher.cancel(); rdpSearchProvider = null; } }