const { Clutter, GObject, Pango, Shell, St } = imports.gi; const Search = imports.ui.search; const Main = imports.ui.main; const Util = imports.misc.util; // Based on ProviderInfo in search.js var RealmProviderInfo = GObject.registerClass( class RealmProviderInfo extends St.Button { _init() { super._init({ style_class: 'search-provider-icon', reactive: false, can_focus: false, accessible_name: "Realms", track_hover: false, y_align: Clutter.ActorAlign.START, }); this._content = new St.BoxLayout({ vertical: false, style_class: 'list-search-provider-content' }); this.set_child(this._content); let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE, icon_name: 'computer' }); let detailsBox = new St.BoxLayout({ style_class: 'list-search-provider-details', vertical: true, x_expand: true }); let nameLabel = new St.Label({ text: "Realms", x_align: Clutter.ActorAlign.START }); this._moreLabel = new St.Label({ x_align: Clutter.ActorAlign.START }); detailsBox.add_actor(nameLabel); detailsBox.add_actor(this._moreLabel); this._content.add_actor(icon); this._content.add_actor(detailsBox); } get PROVIDER_ICON_SIZE() { return 48; } setMoreCount(count) { this._moreLabel.text = ngettext("%d more", "%d more", count).format(count); this._moreLabel.visible = count > 0; } }); var MAX_LIST_SEARCH_RESULTS_ROWS = 10; // Based on ListSearchResult in search.js var RealmSearchResult = GObject.registerClass( class ListSearchResult extends Search.SearchResult { _init(provider, metaInfo, resultsView) { super._init(provider, metaInfo, resultsView); this.style_class = 'list-search-result'; let content = new St.BoxLayout({ style_class: 'list-search-result-content', vertical: false, x_align: Clutter.ActorAlign.FILL, x_expand: true, y_expand: true, }); this.set_child(content); this._termsChangedId = 0; let titleBox = new St.BoxLayout({ style_class: 'list-search-result-title', y_align: Clutter.ActorAlign.CENTER, }); content.add_child(titleBox); // An icon for, or thumbnail of, content let icon = this.metaInfo['createIcon'](this.ICON_SIZE); if (icon) titleBox.add(icon); let title = new St.Label({ text: this.metaInfo['name'], y_align: Clutter.ActorAlign.CENTER, }); titleBox.add_child(title); this.label_actor = title; if (this.metaInfo['description']) { this._descriptionLabel = new St.Label({ style_class: 'list-search-result-description', x_expand: true, x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER, }); this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; content.add_child(this._descriptionLabel); this._termsChangedId = this._resultsView.connect('terms-changed', this._highlightTerms.bind(this)); this._highlightTerms(); } let id = this.metaInfo['id']; if (id != ':new:') { this.configButton = new St.Button({ style_class: 'button', track_hover: true, can_focus: true, child: new St.Icon({ style_class: 'realm-config-icon', icon_name: 'emblem-system-symbolic', icon_size: 24, }), }); this.configButton.connect('clicked', () => { Main.overview.toggle(); Util.spawn(['/usr/libexec/realm-config-ui', id]); }); content.add_child(this.configButton); } this.connect('destroy', this._onDestroy.bind(this)); } get ICON_SIZE() { return 24; } _highlightTerms() { let markup = this._resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]); this._descriptionLabel.clutter_text.set_markup(markup); } _onDestroy() { if (this._termsChangedId) this._resultsView.disconnect(this._termsChangedId); this._termsChangedId = 0; } }); // Based on ListSearchResults in search.js var RealmSearchResults = GObject.registerClass( class RealmSearchResults extends Search.SearchResultsBase { _init(provider, resultsView) { super._init(provider, resultsView); this._container = new St.BoxLayout({ style_class: 'search-section-content' }); this.providerInfo = new RealmProviderInfo(); this.providerInfo.connect('key-focus-in', this._keyFocusIn.bind(this)); this.providerInfo.connect('clicked', () => { Main.overview.toggle(); }); this._container.add_child(this.providerInfo); this._content = new St.BoxLayout({ style_class: 'list-search-results', vertical: true, x_expand: true, }); this._container.add_child(this._content); this._resultDisplayBin.set_child(this._container); } _setMoreCount(count) { this.providerInfo.setMoreCount(count); } _getMaxDisplayedResults() { return MAX_LIST_SEARCH_RESULTS_ROWS; } _clearResultDisplay() { this._content.remove_all_children(); } _createResultDisplay(meta) { return super._createResultDisplay(meta) || new RealmSearchResult(this.provider, meta, this._resultsView); } _addItem(display) { this._content.add_actor(display); } getFirstResult() { if (this._content.get_n_children() > 0) return this._content.get_child_at_index(0); else return null; } }); var RealmSearchProvider = class RealmSearchProvider { constructor() { this._shellRealms = Shell.Realms.get_default(); this.id = 'realms'; this.isRemoteProvider = false; this.canLaunchSearch = false; this.display = null; } createResultDisplay(resultsView) { this.display = new RealmSearchResults(this, resultsView); this.display.connect('notify::focus-child', resultsView._focusChildChanged.bind(resultsView)); this.display.hide(); resultsView._content.add(this.display); } createIcon(size, realm) { if (realm.is_running()) { return new St.Icon({ icon_name: 'emblem-synchronizing', icon_size: size }); } else { return new St.Icon({ icon_name: 'exaile', icon_size: size }); } } createRealmMeta(realm) { let id = realm.get_realm_name(); let description = ''; if (realm.is_running()) { description = `Set realm-${id} as current realm`; } else { description = `Start realm-${id}`; } return { id: id, name: `realm-${id}`, description: description, createIcon: size => { return this.createIcon(size, realm); }, }; } createNewRealmMeta() { return { id: ':new:', name: 'New Realm', description: 'Create a new realm', createIcon: size => { return new St.Icon({ icon_name: 'computer', icon_size: size, }); } } } getResultMetas (ids, callback) { let metas = []; for (let id of ids) { if (id == ":new:") { metas.push(this.createNewRealmMeta()); } else { let realm = this._shellRealms.realm_by_name(id); if (realm && !realm.is_current()) { metas.push(this.createRealmMeta(realm)); } else { log(`No realm found for ${id}`); } } } callback(metas); } activateResult (resultId, _terms) { if (resultId == ':new:') { Main.overview.toggle(); Util.spawn(['/usr/libexec/realm-config-ui', '--new']); return; } let realm = this._shellRealms.realm_by_name(resultId); if (realm) { realm.set_current(); } else { log(`No realm found for ${resultId}`); } } filterResults(results, maxNumber) { return results.slice(0, maxNumber) } getInitialResultSet(terms, callback, _cancellable) { let realms = this._shellRealms.get_all_realms(); let matches = []; if (terms.length == 1 && "new".startsWith(terms[0])) { matches.push(":new:"); } for (let realm of realms) { if (!realm.is_current()) { let name = realm.get_realm_name(); if (terms.every(t => name.indexOf(t) != -1)) { matches.push(name); } } } callback(matches); } getSubsearchResultSet(previousResults, terms, callback, cancellable) { this.getInitialResultSet(terms, callback, cancellable) } }