| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- import * as Main from 'resource:///org/gnome/shell/ui/main.js';
- import St from 'gi://St';
- import {Button as PanelButton} from 'resource:///org/gnome/shell/ui/panelMenu.js';
- import Clutter from 'gi://Clutter';
- import {gnomeExecutables, autocomplete, clear} from './autocomplete.js';
- import {launchApp} from './utils.js';
- export class TopBarSearchEntry {
- _searchButton;
- _searchContainer;
- _searchEntry;
- _searchSuggestion;
- _alive;
- constructor(settings) {
- this._alive = true;
- this._searchButton = new PanelButton(0.0, 'searchEntry', false);
- this._searchContainer = new St.Bin({
- x_expand: true,
- });
- this._searchEntry = new St.Entry({
- style_class: 'custom-search-entry',
- can_focus: true,
- hint_text: 'Type to search…',
- track_hover: true,
- x_expand: true,
- });
- this._searchSuggestion = new St.Label({
- style_class: 'suggestion',
- text: '',
- x_expand: true,
- });
- this._searchEntry.clutter_text.connect('notify::mapped', actor => {
- if (actor.mapped)
- actor.grab_key_focus();
- });
- this._searchContainer.add_child(this._searchSuggestion);
- this._searchContainer.add_child(this._searchEntry);
- this._searchEntry.clutter_text.connect('text-changed', actor => {
- let current = actor.get_text();
- if (current.length > 1 && this._searchSuggestion) {
- let matches = autocomplete(current);
- if (matches.length > 0 && this._searchEntry) {
- let match = matches[0];
- const ct = this._searchEntry.get_clutter_text();
- const layout = ct.get_layout();
- const [textW] = layout.get_pixel_size();
- const themeNode = this._searchEntry.get_theme_node();
- const leftPad = themeNode.get_padding(St.Side.LEFT);
- const x = leftPad + textW;
- this._searchSuggestion.set_style(`color: rgba(255,255,255,0.35); margin-left: ${x + 4}px;`);
- this._searchSuggestion.set_text(match.slice(current.length));
- } else {
- this._searchSuggestion.set_text('');
- }
- } else if (this._searchSuggestion) {
- this._searchSuggestion.set_text('');
- }
- });
- let completeText = () => {
- const typed = this._searchEntry?.get_text();
- const ct = this._searchEntry?.get_clutter_text();
- if (!typed || !ct)
- return;
- let full = typed + this._searchSuggestion?.get_text();
- this._searchEntry?.set_text(full);
- ct.set_cursor_position(full.length);
- this._searchSuggestion?.set_text('');
- };
- this._searchEntry.clutter_text.connect('key-press-event', (ct, event) => {
- const key = event.get_key_symbol();
- if (key === Clutter.KEY_KP_Right || key === Clutter.KEY_Right) {
- // Only accept if cursor is at end and a suggestion exists
- const typed = this._searchEntry?.get_text();
- if (typed) {
- completeText();
- return Clutter.EVENT_STOP;
- }
- }
- return Clutter.EVENT_PROPAGATE;
- });
- this._searchEntry.connect('captured-event', (actor, event) => {
- if (event.type() !== Clutter.EventType.KEY_PRESS)
- return Clutter.EVENT_PROPAGATE;
- const sym = event.get_key_symbol();
- if (sym === Clutter.KEY_Tab || sym === Clutter.KEY_ISO_Left_Tab) {
- completeText();
- return Clutter.EVENT_STOP;
- }
- return Clutter.EVENT_PROPAGATE;
- });
- this._searchEntry.clutter_text.connect('activate', actor => {
- let query = actor.get_text().trim().toLowerCase();
- if (query === '') {
- this.destroy();
- } else if (gnomeExecutables?.get(query)) {
- gnomeExecutables.get(query)?.launch([], null);
- this.destroy();
- } else if (launchApp([query])) {
- this.destroy();
- } else {
- actor.set_text('');
- this._searchEntry?.set_style('border: 2px solid red;');
- }
- });
- this._searchButton.add_child(this._searchContainer);
- let positionInt = settings.get_int('search-entry-position');
- let position;
- if (positionInt === 0)
- position = 'left';
- else if (positionInt === 1)
- position = 'center';
- else
- position = 'right';
- Main.panel.addToStatusArea('SearchEntry', this._searchButton, 0, position);
- }
- isAlive() {
- return this._alive;
- }
- destroy() {
- this._alive = false;
- if (this._searchButton) {
- this._searchButton?.destroy();
- this._searchContainer = undefined;
- this._searchEntry = undefined;
- this._searchButton = undefined;
- this._searchSuggestion = undefined;
- }
- clear();
- }
- }
|