[gnome-shell/T27795: 89/138] Add new class for the desktop search entry widget: OverviewEntry



commit 5bb1fa08598a93d3071ab4655ff3731c7ab67bce
Author: Mario Sanchez Prada <mario endlessm com>
Date:   Wed May 17 18:15:31 2017 +0100

    Add new class for the desktop search entry widget: OverviewEntry
    
    This will render the search entry box with the desired style.
    
    https://phabricator.endlessm.com/T13041

 data/gnome-shell-theme.gresource.xml      |   1 +
 data/theme/gnome-shell-sass/_endless.scss |  60 ++++++
 data/theme/process-working-dark.svg       | 261 +++++++++++++++++++++++++
 js/ui/shellEntry.js                       | 315 +++++++++++++++++++++++++++++-
 4 files changed, 635 insertions(+), 2 deletions(-)
---
diff --git a/data/gnome-shell-theme.gresource.xml b/data/gnome-shell-theme.gresource.xml
index 583e700788..91ce41da77 100644
--- a/data/gnome-shell-theme.gresource.xml
+++ b/data/gnome-shell-theme.gresource.xml
@@ -43,6 +43,7 @@
     <file>hot-corner-symbolic.svg</file>
     <file>hot-corner-rtl-symbolic.svg</file>
     <file>mini-icon-active-indicator.png</file>
+    <file>process-working-dark.svg</file>
     <file>system-logout.png</file>
   </gresource>
 </gresources>
diff --git a/data/theme/gnome-shell-sass/_endless.scss b/data/theme/gnome-shell-sass/_endless.scss
index 2a46fafdee..9e0ce0e546 100644
--- a/data/theme/gnome-shell-sass/_endless.scss
+++ b/data/theme/gnome-shell-sass/_endless.scss
@@ -376,3 +376,63 @@ popup-separator-menu-item {
         spacing: 10px;
     }
 }
+
+// Desktop Search (text entry widget)
+
+#searchEntry {
+    width: 350px;
+    height: 38px;
+
+    margin-top: 8px;
+    padding: 0 12px 0 0;
+
+    font-family: lato, sans-serif;
+    font-size: 11.5pt;
+
+    color: #484645;
+    selected-color: #ededed;
+    caret-color: #333;
+    background-color: rgba(255, 255, 255, 0.8);
+
+    border-width: 0;
+    border-radius: 19px;
+    box-shadow: 0px 0px 4px rgba(0,0,0,0.7);
+
+    -minimum-vpadding: 48px;
+
+    .search-entry-text-hint {
+        padding-left: 6px;
+        padding-right: 6px;
+        padding-bottom: 2px;
+
+        font-family: lato, sans-serif;
+        font-size: 12pt;
+        color: #424040;
+    }
+
+    .search-icon {
+        background-gradient-start: rgba(255,95,42,0.9);
+        background-gradient-end: rgba(248,63,0,0.9);
+        background-gradient-direction: vertical;
+
+        color: white;
+
+        width: 38px;
+        height: 38px;
+        border-radius: 19px;
+
+        box-shadow: inset 0 -1px 1px rgba(0,0,0,0.25);
+    }
+
+    &.low-resolution {
+        width: 300px;
+
+        -minimum-vpadding: 20px;
+    }
+
+    &:hover, &:focus { background-color: rgba(255, 255, 255, 0.95); }
+    &:rtl {
+        padding-left: 12px;
+        padding-right: 0px;
+    }
+}
diff --git a/data/theme/process-working-dark.svg b/data/theme/process-working-dark.svg
new file mode 100644
index 0000000000..ad8b419d2c
--- /dev/null
+++ b/data/theme/process-working-dark.svg
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   id="svg5369"
+   version="1.1"
+   inkscape:version="0.48+devel r10053 custom"
+   width="96"
+   height="48"
+   sodipodi:docname="process-working.svg"
+   style="display:inline">
+  <metadata
+     id="metadata5375">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs5373" />
+  <sodipodi:namedview
+     pagecolor="#808080"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1975"
+     inkscape:window-height="1098"
+     id="namedview5371"
+     showgrid="true"
+     borderlayer="true"
+     inkscape:showpageshadow="false"
+     inkscape:zoom="16"
+     inkscape:cx="53.997662"
+     inkscape:cy="22.367695"
+     inkscape:window-x="1600"
+     inkscape:window-y="33"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="layer2">
+    <inkscape:grid
+       type="xygrid"
+       id="grid11933"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <g
+     inkscape:groupmode="layer"
+     id="layer1"
+     inkscape:label="tiles"
+     style="display:none">
+    <rect
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect12451"
+       width="24"
+       height="24"
+       x="0"
+       y="0" />
+    <rect
+       y="24"
+       x="0"
+       height="24"
+       width="24"
+       id="rect12453"
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 />
+    <rect
+       y="0"
+       x="24"
+       height="24"
+       width="24"
+       id="rect12455"
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 />
+    <rect
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect12457"
+       width="24"
+       height="24"
+       x="24"
+       y="24" />
+    <rect
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect12459"
+       width="24"
+       height="24"
+       x="48"
+       y="0" />
+    <rect
+       y="24"
+       x="48"
+       height="24"
+       width="24"
+       id="rect12461"
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 />
+    <rect
+       y="0"
+       x="72"
+       height="24"
+       width="24"
+       id="rect12463"
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 />
+    <rect
+       
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect12465"
+       width="24"
+       height="24"
+       x="72"
+       y="24" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="spinner">
+    <g
+       transform="matrix(0.28240106,0,0,0.28240106,146.92015,-382.52444)"
+       id="g10450-5"
+       style="display:inline">
+      <path
+         inkscape:connector-curvature="0"
+         
style="opacity:0.6;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m -477.76072,1373.3569 0,9.4717"
+         id="path18768"
+         sodipodi:nodetypes="cc"
+         inkscape:transform-center-y="-4.6808838" />
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:transform-center-y="-3.3099227"
+         sodipodi:nodetypes="cc"
+         id="path18770"
+         d="m -461.0171,1380.2922 -7.23427,7.3824"
+         
style="opacity:0.7;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:transform-center-x="-3.3098966" />
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:transform-center-x="-4.6808962"
+         
style="opacity:0.8;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m -454.08163,1397.0359 -9.47165,0"
+         id="path18772"
+         sodipodi:nodetypes="cc"
+         inkscape:transform-center-y="-2.6596956e-05" />
+      <path
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc"
+         id="path18774"
+         d="m -461.01709,1413.7796 -6.93831,-7.0864"
+         
style="opacity:0.9;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:transform-center-x="-3.3098966"
+         inkscape:transform-center-y="3.3098652" />
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:transform-center-y="4.6808757"
+         
style="color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m -477.76074,1420.715 9e-5,-9.4716"
+         id="path18776"
+         sodipodi:nodetypes="cc" />
+      <path
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc"
+         id="path18778"
+         d="m -494.50442,1413.7796 6.79048,-6.9384"
+         
style="opacity:0.3;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:transform-center-y="3.3098769"
+         inkscape:transform-center-x="3.3098883" />
+      <path
+         inkscape:connector-curvature="0"
+         inkscape:transform-center-x="4.6808941"
+         
style="opacity:0.4;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m -501.43987,1397.0359 9.47174,0"
+         id="path18780"
+         sodipodi:nodetypes="cc"
+         inkscape:transform-center-y="-2.6596956e-05" />
+      <path
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc"
+         id="path18782"
+         d="m -494.5044,1380.2922 6.64243,6.9384"
+         
style="opacity:0.5;color:#000000;fill:none;stroke:#333333;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:transform-center-x="3.3098902"
+         inkscape:transform-center-y="-3.3099302" />
+    </g>
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#g10450-5"
+       id="use4981"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,36,-4.9705636)"
+       width="400"
+       height="400" />
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#use4981"
+       id="use4983"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,43.032478,-21.909695)"
+       width="400"
+       height="400" />
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#use4983"
+       id="use4985"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,50.081986,-38.904617)"
+       width="400"
+       height="400" />
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#use4985"
+       id="use4987"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,-38.919996,-31.872139)"
+       width="400"
+       height="400" />
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#use4987"
+       id="use4989"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,52.986628,2.0890543)"
+       width="400"
+       height="400" />
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#use4989"
+       id="use4991"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,60.013026,-14.912936)"
+       width="400"
+       height="400" />
+    <use
+       style="display:inline"
+       x="0"
+       y="0"
+       xlink:href="#use4991"
+       id="use4993"
+       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,67.022396,-31.859127)"
+       width="400"
+       height="400" />
+  </g>
+</svg>
diff --git a/js/ui/shellEntry.js b/js/ui/shellEntry.js
index e5b9617024..1f410d3428 100644
--- a/js/ui/shellEntry.js
+++ b/js/ui/shellEntry.js
@@ -1,16 +1,26 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /* exported addContextMenu */
 
-const { Clutter, Shell, St } = imports.gi;
+const { Clutter, Gio, GObject, Gtk, Shell, St } = imports.gi;
 
+const Animation = imports.ui.animation;
 const BoxPointer = imports.ui.boxpointer;
 const Main = imports.ui.main;
+const Panel = imports.ui.panel;
 const Params = imports.misc.params;
 const PopupMenu = imports.ui.popupMenu;
 
+const Util = imports.misc.util;
+
+const SPINNER_ICON_SIZE = 24;
+const SPINNER_MIN_DURATION = 1000;
+
+const OVERVIEW_ENTRY_BLINK_DURATION = 400;
+const OVERVIEW_ENTRY_BLINK_BRIGHTNESS = 1.4;
+
 var EntryMenu = class extends PopupMenu.PopupMenu {
     constructor(entry) {
-        super(entry, 0, St.Side.TOP);
+        super(entry, 0.025, St.Side.TOP);
 
         this._entry = entry;
         this._clipboard = St.Clipboard.get_default();
@@ -115,6 +125,307 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
     }
 };
 
+var OverviewEntry = GObject.registerClass({
+    Signals: {
+        'search-activated': {},
+        'search-active-changed': {},
+        'search-navigate-focus': { param_types: [GObject.TYPE_INT] },
+        'search-terms-changed': {},
+    },
+    Properties: {
+        'blinkBrightness': GObject.ParamSpec.double(
+            'blinkBrightness',
+            'blinkBrightness',
+            'blinkBrightness',
+            GObject.ParamFlags.READWRITE,
+            0, 10, 0)
+    }
+}, class OverviewEntry extends St.Entry {
+    _init() {
+        this._active = false;
+
+        this._capturedEventId = 0;
+
+        let primaryIcon = new St.Icon({
+            icon_name: 'edit-find-symbolic',
+            style_class: 'search-icon',
+            icon_size: 16,
+            track_hover: true,
+        });
+
+        let iconFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working-dark.svg')
+        this._spinnerAnimation = new Animation.AnimatedIcon(iconFile, SPINNER_ICON_SIZE);
+        this._spinnerAnimation.actor.hide();
+
+        // Set the search entry's text based on the current search engine
+        let entryText;
+        let searchEngine = Util.getSearchEngineName();
+
+        if (searchEngine != null)
+            entryText = _("Search %s and more…").format(searchEngine);
+        else
+            entryText = _("Search the internet and more…");
+
+        let hintActor = new St.Label({ text: entryText,
+                                       style_class: 'search-entry-text-hint' });
+
+        super._init({
+            name: 'searchEntry',
+            track_hover: true,
+            reactive: true,
+            can_focus: true,
+            hint_text: '',
+            hint_actor: hintActor,
+            primary_icon: primaryIcon,
+            secondary_icon: this._spinnerAnimation.actor,
+            x_align: Clutter.ActorAlign.CENTER,
+            y_align: Clutter.ActorAlign.CENTER,
+        });
+
+        this._blinkBrightnessEffect = new Clutter.BrightnessContrastEffect({
+            enabled: false,
+        });
+        this.add_effect(this._blinkBrightnessEffect);
+
+        addContextMenu(this);
+
+        this.connect('primary-icon-clicked', () => {
+            this.grab_key_focus();
+        });
+        this.connect('notify::mapped', this._onMapped.bind(this));
+        this.clutter_text.connect('key-press-event', this._onKeyPress.bind(this));
+        this.clutter_text.connect('text-changed', this._onTextChanged.bind(this));
+        global.stage.connect('notify::key-focus', this._onStageKeyFocusChanged.bind(this));
+    }
+
+    _isActivated() {
+        return !this.hint_actor.visible;
+    }
+
+    _getTermsForSearchString(searchString) {
+        searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
+        if (searchString == '')
+            return [];
+
+        let terms = searchString.split(/\s+/);
+        return terms;
+    }
+
+    _onCapturedEvent(actor, event) {
+        if (event.type() != Clutter.EventType.BUTTON_PRESS)
+            return false;
+
+        let source = event.get_source();
+        if (source != this.clutter_text &&
+            !Main.layoutManager.keyboardBox.contains(source)) {
+            // If the user clicked outside after activating the entry,
+            // drop the focus from the search bar, but avoid resetting
+            // the entry state.
+            // If no search terms entered were entered, also reset the
+            // entry to its initial state.
+            if (this.clutter_text.text == '')
+                this.resetSearch();
+            else
+                this._stopSearch();
+        }
+
+        return false;
+    }
+
+    _onKeyPress(entry, event) {
+        let symbol = event.get_key_symbol();
+        if (symbol == Clutter.Escape && this._isActivated()) {
+            this.resetSearch();
+            return true;
+        }
+
+        if (!this.active)
+            return false;
+
+        let arrowNext, nextDirection;
+        if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
+            arrowNext = Clutter.Left;
+            nextDirection = Gtk.DirectionType.LEFT;
+        } else {
+            arrowNext = Clutter.Right;
+            nextDirection = Gtk.DirectionType.RIGHT;
+        }
+
+        if (symbol == Clutter.Down)
+            nextDirection = Gtk.DirectionType.DOWN;
+
+        if ((symbol == arrowNext && this.clutter_text.position == -1) ||
+            (symbol == Clutter.Down)) {
+            this.emit('search-navigate-focus', nextDirection);
+            return true;
+        } else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
+            this._activateSearch();
+            return true;
+        }
+
+        return false;
+    }
+
+    _onMapped() {
+        // The entry might get mapped because of the clone, so we also
+        // have to check if the actual overview actor is visible.
+        if (this.mapped && Main.layoutManager.overviewGroup.visible) {
+            // Enable 'find-as-you-type'
+            this._capturedEventId = global.stage.connect('captured-event',
+                                                         this._onCapturedEvent.bind(this));
+
+            this.clutter_text.set_cursor_visible(true);
+            // Move the cursor at the end of the current text
+            let buffer = this.clutter_text.get_buffer();
+            let nChars = buffer.get_length();
+            this.clutter_text.set_selection(nChars, nChars);
+        } else {
+            // Disable 'find-as-you-type'
+            if (this._capturedEventId > 0) {
+                global.stage.disconnect(this._capturedEventId);
+                this._capturedEventId = 0;
+            }
+        }
+    }
+
+    _onStageKeyFocusChanged() {
+        let focus = global.stage.get_key_focus();
+        let appearFocused = this.contains(focus);
+
+        this.clutter_text.set_cursor_visible(appearFocused);
+
+        if (appearFocused)
+            this.add_style_pseudo_class('focus');
+        else
+            this.remove_style_pseudo_class('focus');
+    }
+
+    _onTextChanged (se, prop) {
+        this.emit('search-terms-changed');
+        let terms = this._getTermsForSearchString(this.get_text());
+        this.active = (terms.length > 0);
+    }
+
+    _searchCancelled() {
+        // Leave the entry focused when it doesn't have any text;
+        // when replacing a selected search term, Clutter emits
+        // two 'text-changed' signals, one for deleting the previous
+        // text and one for the new one - the second one is handled
+        // incorrectly when we remove focus
+        // (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
+        if (this.clutter_text.text != '')
+            this.resetSearch();
+    }
+
+    _shouldTriggerSearch(symbol) {
+        let unicode = Clutter.keysym_to_unicode(symbol);
+        if (unicode == 0)
+            return symbol == Clutter.BackSpace && this.active;
+
+        return this._getTermsForSearchString(String.fromCharCode(unicode)).length > 0;
+    }
+
+    _activateSearch() {
+        this.emit('search-activated');
+    }
+
+    _stopSearch() {
+        global.stage.set_key_focus(null);
+    }
+
+    _startSearch(event) {
+        global.stage.set_key_focus(this.clutter_text);
+        this.clutter_text.event(event, false);
+    }
+
+    resetSearch () {
+        this._stopSearch();
+        this.text = '';
+
+        this.clutter_text.set_cursor_visible(true);
+        this.clutter_text.set_selection(0, 0);
+    }
+
+    handleStageEvent(event) {
+        let symbol = event.get_key_symbol();
+
+        if (symbol == Clutter.Escape && this.active) {
+            this.resetSearch();
+            return true;
+        }
+
+        if (this._shouldTriggerSearch(symbol)) {
+            this._startSearch(event);
+            return true;
+        }
+
+        return false;
+    }
+
+    setSpinning(visible) {
+        if (visible) {
+            this._spinnerAnimation.play();
+            this._spinnerAnimation.actor.show();
+        } else {
+            this._spinnerAnimation.stop();
+            this._spinnerAnimation.actor.hide();
+        }
+    }
+
+    get blinkBrightness() {
+        return this._blinkBrightness;
+    }
+
+    set blinkBrightness(v) {
+        this._blinkBrightness = v;
+        this._blinkBrightnessEffect.enabled = this._blinkBrightness !== 1;
+        let colorval = this._blinkBrightness * 127;
+        this._blinkBrightnessEffect.brightness = new Clutter.Color({
+            red: colorval,
+            green: colorval,
+            blue: colorval,
+        });
+    }
+
+    blink() {
+        this.blinkBrightness = 1;
+        this.ease({
+            blinkBrightness: OVERVIEW_ENTRY_BLINK_BRIGHTNESS,
+            duration: OVERVIEW_ENTRY_BLINK_DURATION / 2,
+            mode: Clutter.AnimationMode.EASE_IN_QUAD,
+            onComplete: () => {
+                this.ease({
+                    blinkBrightness: 1,
+                    duration: OVERVIEW_ENTRY_BLINK_DURATION / 2,
+                    mode: Clutter.AnimationMode.EASE_IN_QUAD,
+                });
+            },
+        });
+
+    }
+
+    set active(value) {
+        if (value == this._active)
+            return;
+
+        this._active = value;
+        this._ongoing = false;
+
+        if (!this._active)
+            this._searchCancelled();
+
+        this.emit('search-active-changed');
+    }
+
+    get active() {
+        return this._active;
+    }
+
+    getSearchTerms() {
+        return this._getTermsForSearchString(this.get_text());
+    }
+});
+
 function _setMenuAlignment(entry, stageX) {
     let [success, entryX] = entry.transform_stage_point(stageX, 0);
     if (success)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]