[gnome-shell] viewSelector: add Applications pane and search entry to Ctrl-Alt-Tab



commit 0cccf1d4cc7510905681ab9444c97098ec22c09e
Author: Dan Winship <danw gnome org>
Date:   Wed Feb 23 14:21:47 2011 -0500

    viewSelector: add Applications pane and search entry to Ctrl-Alt-Tab
    
    Add Ctrl-Alt-Tab support to ViewTab, and fix the Applications pane to
    scroll to track the keyboard focus.
    
    The Windows pane can be switched to, but navigation within the pane is
    not yet implemented.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=618887

 data/theme/gnome-shell.css |    4 ++++
 js/ui/appDisplay.js        |   41 ++++++++++++++++++++++++++++++++++++++++-
 js/ui/overview.js          |    4 ++--
 js/ui/viewSelector.js      |   39 ++++++++++++++++++++++++++++-----------
 src/st/st-scroll-view.c    |    3 ++-
 5 files changed, 76 insertions(+), 15 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index cfcec9e..526b059 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -576,6 +576,10 @@ StTooltip StLabel {
     background-position: 10px 10px;
 }
 
+.app-filter:focus {
+    outline: 1px solid #aaa;
+}
+
 .dash-item-container > .app-well-app {
     padding: 4px 8px;
 }
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 0433cec..ffd49fa 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -23,6 +23,7 @@ const Workspace = imports.ui.workspace;
 const Params = imports.misc.params;
 
 const MENU_POPUP_TIMEOUT = 600;
+const SCROLL_TIME = 0.1;
 
 function AlphabeticalView() {
     this._init();
@@ -67,6 +68,7 @@ AlphabeticalView.prototype = {
         let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
 
         this._grid.addItem(appIcon.actor);
+        appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
 
         appIcon._appInfo = appInfo;
         if (this._filterApp && !this._filterApp(appInfo))
@@ -75,6 +77,28 @@ AlphabeticalView.prototype = {
         this._apps.push(appIcon);
     },
 
+    _ensureIconVisible: function(icon) {
+        let adjustment = this.actor.vscroll.adjustment;
+        let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
+
+        let offset = 0;
+        let vfade = this.actor.get_effect("vfade");
+        if (vfade)
+            offset = vfade.fade_offset;
+
+        if (icon.y < value + offset)
+            value = Math.max(0, icon.y - offset);
+        else if (icon.y + icon.height > value + pageSize - offset)
+            value = Math.min(upper, icon.y + icon.height + offset - pageSize);
+        else
+            return;
+
+        Tweener.addTween(adjustment,
+                         { value: value,
+                           time: SCROLL_TIME,
+                           transition: 'easeOutQuad' });
+    },
+
     setFilter: function(filter) {
         this._filterApp = filter;
         for (let i = 0; i < this._apps.length; i++)
@@ -128,6 +152,12 @@ ViewByCategories.prototype = {
             }));
 
         this._sections = [];
+
+        // We need a dummy actor to catch the keyboard focus if the
+        // user Ctrl-Alt-Tabs here before the deferred work creates
+        // our real contents
+        this._focusDummy = new St.Bin({ can_focus: true });
+        this.actor.add(this._focusDummy);
     },
 
     _scrollFilter: function(actor, event) {
@@ -166,7 +196,8 @@ ViewByCategories.prototype = {
     _addFilter: function(name, num) {
         let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
                                      style_class: 'app-filter',
-                                     x_align: St.Align.START });
+                                     x_align: St.Align.START,
+                                     can_focus: true });
         this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
         button.connect('clicked', Lang.bind(this, function() {
             this._selectCategory(num);
@@ -201,6 +232,14 @@ ViewByCategories.prototype = {
             this._addFilter(sections[i], i);
 
         this._selectCategory(-1);
+
+        if (this._focusDummy) {
+            let focused = this._focusDummy.has_key_focus();
+            this._focusDummy.destroy();
+            this._focusDummy = null;
+            if (focused)
+                this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
+        }
     }
 };
 
diff --git a/js/ui/overview.js b/js/ui/overview.js
index ad02d13..6d86bda 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -180,10 +180,10 @@ Overview.prototype = {
         this._group.add_actor(this.viewSelector.actor);
 
         this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
-        this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor);
+        this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor, 'text-x-generic');
 
         let appView = new AppDisplay.AllAppDisplay();
-        this.viewSelector.addViewTab(_("Applications"), appView.actor);
+        this.viewSelector.addViewTab(_("Applications"), appView.actor, 'system-run');
 
         // Default search providers
         this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js
index 7e5fa27..5cad9cd 100644
--- a/js/ui/viewSelector.js
+++ b/js/ui/viewSelector.js
@@ -1,6 +1,7 @@
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 
 const Clutter = imports.gi.Clutter;
+const Gtk = imports.gi.Gtk;
 const Mainloop = imports.mainloop;
 const Meta = imports.gi.Meta;
 const Signals = imports.signals;
@@ -15,12 +16,12 @@ const Search = imports.ui.search;
 const SearchDisplay = imports.ui.searchDisplay;
 const Tweener = imports.ui.tweener;
 
-function BaseTab(titleActor, pageActor) {
-    this._init(titleActor, pageActor);
+function BaseTab(titleActor, pageActor, name, a11yIcon) {
+    this._init(titleActor, pageActor, name, a11yIcon);
 }
 
 BaseTab.prototype = {
-    _init: function(titleActor, pageActor) {
+    _init: function(titleActor, pageActor, name, a11yIcon) {
         this.title = titleActor;
         this.page = new St.Bin({ child: pageActor,
                                  x_align: St.Align.START,
@@ -29,6 +30,14 @@ BaseTab.prototype = {
                                  y_fill: true,
                                  style_class: 'view-tab-page' });
 
+        if (this.title.can_focus) {
+            Main.ctrlAltTabManager.addGroup(this.title, name, a11yIcon);
+        } else {
+            Main.ctrlAltTabManager.addGroup(this.page, name, a11yIcon,
+                                            { proxy: this.title,
+                                              focusCallback: Lang.bind(this, this._a11yFocus) });
+        }
+
         this.visible = false;
     },
 
@@ -56,6 +65,11 @@ BaseTab.prototype = {
                          });
     },
 
+    _a11yFocus: function() {
+        this._activate();
+        this.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
+    },
+
     _activate: function() {
         this.emit('activated');
     }
@@ -63,19 +77,19 @@ BaseTab.prototype = {
 Signals.addSignalMethods(BaseTab.prototype);
 
 
-function ViewTab(label, pageActor) {
-    this._init(label, pageActor);
+function ViewTab(label, pageActor, a11yIcon) {
+    this._init(label, pageActor, a11yIcon);
 }
 
 ViewTab.prototype = {
     __proto__: BaseTab.prototype,
 
-    _init: function(label, pageActor) {
+    _init: function(label, pageActor, a11yIcon) {
         let titleActor = new St.Button({ label: label,
                                          style_class: 'view-tab-title' });
         titleActor.connect('clicked', Lang.bind(this, this._activate));
 
-        BaseTab.prototype._init.call(this, titleActor, pageActor);
+        BaseTab.prototype._init.call(this, titleActor, pageActor, label, a11yIcon);
     }
 };
 
@@ -101,7 +115,8 @@ SearchTab.prototype = {
                                         active; it should not exceed ~30
                                         characters. */
                                      hint_text: _("Type to search..."),
-                                     track_hover: true });
+                                     track_hover: true,
+                                     can_focus: true });
         this._text = this._entry.clutter_text;
         this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
 
@@ -118,7 +133,9 @@ SearchTab.prototype = {
         this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
         BaseTab.prototype._init.call(this,
                                      this._entry,
-                                     this._searchResults.actor);
+                                     this._searchResults.actor,
+                                     _("Search"),
+                                     'edit-find');
 
         this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
         this._text.connect('activate', Lang.bind(this, function (se) {
@@ -366,8 +383,8 @@ ViewSelector.prototype = {
         }));
     },
 
-    addViewTab: function(title, pageActor) {
-        let viewTab = new ViewTab(title, pageActor);
+    addViewTab: function(title, pageActor, a11yIcon) {
+        let viewTab = new ViewTab(title, pageActor, a11yIcon);
         this._tabs.push(viewTab);
         this._tabBox.add(viewTab.title);
         this._addTab(viewTab);
diff --git a/src/st/st-scroll-view.c b/src/st/st-scroll-view.c
index 3f7c12a..618648a 100644
--- a/src/st/st-scroll-view.c
+++ b/src/st/st-scroll-view.c
@@ -176,7 +176,8 @@ st_scroll_view_set_vfade (StScrollView *self,
       if (priv->vfade_effect == NULL)
         priv->vfade_effect = g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
 
-      clutter_actor_add_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
+      clutter_actor_add_effect_with_name (CLUTTER_ACTOR (self), "vfade",
+                                          CLUTTER_EFFECT (priv->vfade_effect));
     }
    else
     {



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