[gnome-shell] Implement newer design for "more apps" view



commit 690be611eee4c00b56acd6f7d0c94b98b662cabf
Author: Maxim Ermilov <zaspire rambler ru>
Date:   Tue Feb 16 03:50:36 2010 +0300

    Implement newer design for "more apps" view
    
    Replace the old GenericDisplay-based system with one which reuses
    the WellGrid class and uses a new scrolling container.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=609015

 data/Makefile.am           |    1 +
 data/theme/gnome-shell.css |   28 ++++++
 js/ui/appDisplay.js        |  232 ++++++++++++++-----------------------------
 js/ui/dash.js              |   27 +++---
 js/ui/overview.js          |   13 +--
 5 files changed, 122 insertions(+), 179 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index ccd6263..c191084 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -35,6 +35,7 @@ dist_theme_DATA =				\
 	theme/scroll-vhandle.svg        \
 	theme/section-back.svg          \
 	theme/section-more.svg          \
+	theme/section-more-open.svg          \
 	theme/single-view-active.svg          \
 	theme/single-view.svg          \
 	theme/ws-switch-arrow-left.svg		\
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 1420b1e..bf18b05 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -307,6 +307,12 @@ StTooltip {
     height: 9px;
 }
 
+.more-link-expander.open {
+    background-image: url("section-more-open.svg");
+    width: 9px;
+    height: 9px;
+}
+
 .dash-pane {
     background-color: rgba(0,0,0,0.95);
     border: 1px solid #262626;
@@ -383,11 +389,33 @@ StTooltip {
 
 /* Apps */
 
+.overview-pane {
+    width: 440px;
+}
+
 #dashAppWell {
     spacing: 6px;
     -shell-grid-item-size: 70px;
 }
 
+.all-app {
+    border-radius: 10px;
+    background-color: rgba(0,0,0,0.95);
+    border: 1px solid #262626;
+    color: #ffffff;
+    height: 400px;
+}
+
+.all-app-controls-panel {
+    height: 30px;
+}
+
+.all-app-scroll-view {
+    padding-right: 10px;
+    padding-left: 10px;
+    padding-bottom: 10px;
+}
+
 .app-well-app {
     border: 1px solid #181818;
     border-radius: 4px;
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 026ec11..c300851 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -24,195 +24,110 @@ const Workspace = imports.ui.workspace;
 const APPICON_SIZE = 48;
 const WELL_MAX_COLUMNS = 8;
 
-/* This class represents a single display item containing information about an application.
- *
- * appInfo - AppInfo object containing information about the application
- */
-function AppDisplayItem(appInfo) {
-    this._init(appInfo);
+function AllAppView() {
+    this._init();
 }
 
-AppDisplayItem.prototype = {
-    __proto__:  GenericDisplay.GenericDisplayItem.prototype,
-
-    _init : function(appInfo) {
-        GenericDisplay.GenericDisplayItem.prototype._init.call(this);
-        this._appInfo = appInfo;
-
-        this._setItemInfo(appInfo.get_name(), appInfo.get_description());
+AllAppView.prototype = {
+    _init: function(apps) {
+        this.actor = new St.BoxLayout({ vertical: true });
+        this._grid = new WellGrid(true);
+        this._appSystem = Shell.AppSystem.get_default();
+        this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true });
     },
 
-    getId: function() {
-        return this._appInfo.get_id();
+    _removeAll: function() {
+        this._grid.removeAll();
+        this._apps = [];
     },
 
-    //// Public method overrides ////
-
-    // Opens an application represented by this display item.
-    launch : function() {
-        let appSys = Shell.AppSystem.get_default();
-        let app = appSys.get_app(this._appInfo.get_id());
-        let windows = app.get_windows();
-        if (windows.length > 0) {
-            let mostRecentWindow = windows[0];
-            Main.activateWindow(mostRecentWindow);
-        } else {
-            this._appInfo.launch();
-        }
-    },
+    _addApp: function(app) {
+        let App = new AppWellIcon(this._appSystem.get_app(app.get_id()));
+        App.connect('launching', Lang.bind(this, function() {
+            this.emit('launching');
+        }));
+        App._draggable.connect('drag-begin', Lang.bind(this, function() {
+            this.emit('drag-begin');
+        }));
 
-    //// Protected method overrides ////
+        this._grid.addItem(App.actor);
 
-    // Returns an icon for the item.
-    _createIcon : function() {
-        return this._appInfo.create_icon_texture(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
+        this._apps.push(App);
     },
 
-    // Returns a preview icon for the item.
-    _createPreviewIcon : function() {
-        return this._appInfo.create_icon_texture(GenericDisplay.PREVIEW_ICON_SIZE);
-    },
+    refresh: function(apps) {
+        let ids = [];
+        for (let i in apps)
+            ids.push(i);
+        ids.sort(function(a, b) {
+            return apps[a].get_name().localeCompare(apps[b].get_name());
+        });
+
+        this._removeAll();
 
-    shellWorkspaceLaunch: function() {
-        this.launch();
+        for (let i = 0; i < ids.length; i++) {
+            this._addApp(apps[ids[i]]);
+        }
     }
 };
 
+Signals.addSignalMethods(AllAppView.prototype);
+
 /* This class represents a display containing a collection of application items.
- * The applications are sorted based on their popularity by default, and based on
- * their name if some search filter is applied.
- *
- * showPrefs - a boolean indicating if this AppDisplay should contain preference
- *             applets, rather than applications
+ * The applications are sorted based on their name.
  */
-function AppDisplay(showPrefs, flags) {
-    this._init(showPrefs, flags);
+function AllAppDisplay() {
+    this._init();
 }
 
-AppDisplay.prototype = {
-    __proto__:  GenericDisplay.GenericDisplay.prototype,
-
-    _init : function(showPrefs, flags) {
-        GenericDisplay.GenericDisplay.prototype._init.call(this, flags);
-
-        this._showPrefs = showPrefs;
-
-        this._menus = [];
-        this._menuDisplays = [];
-        // map<search term, map<appId, true>>
-        // We use a map of appIds instead of an array to ensure that we don't have duplicates and for easier lookup.
-        this._menuSearchAppMatches = {};
-
+AllAppDisplay.prototype = {
+    _init: function() {
         this._appSystem = Shell.AppSystem.get_default();
-        this._appsStale = true;
-        this._appSystem.connect('installed-changed', Lang.bind(this, function(appSys) {
-            this._appsStale = true;
-            this._redisplay(GenericDisplay.RedisplayFlags.NONE);
+        this._appSystem.connect('installed-changed', Lang.bind(this, function() {
+            Main.queueDeferredWork(this._workId);
         }));
-    },
 
-    //// Private ////
+        let bin = new St.BoxLayout({ style_class: 'all-app-controls-panel' });
+        this.actor = new St.BoxLayout({ style_class: 'all-app', vertical: true });
+        this.actor.hide();
 
-    _addApp: function(appInfo) {
-        let appId = appInfo.get_id();
-        this._allItems[appId] = appInfo;
-    },
+        let view = new St.ScrollView({ x_fill: true, y_fill: false, style_class: 'all-app-scroll-view' });
+        this._scrollView = view;
+        this.actor.add(bin);
+        this.actor.add(view, { expand: true, y_fill: false, y_align: St.Align.START });
 
-    //// Protected method overrides ////
+        this._appView = new AllAppView();
+        this._appView.connect('launching', Lang.bind(this, this.close));
+        this._appView.connect('drag-begin', Lang.bind(this, this.close));
+        this._scrollView.add_actor(this._appView.actor);
 
-    // Gets information about all applications by calling Gio.app_info_get_all().
-    _refreshCache : function() {
-        if (!this._appsStale)
-            return true;
-        this._allItems = {};
+        this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS);
 
-        if (this._showPrefs) {
-            // Get the desktop file ids for settings/preferences.
-            // These are used for search results, but not in the app menus.
-            let settings = this._appSystem.get_all_settings();
-            for (let i = 0; i < settings.length; i++) {
-                let app = settings[i];
-                this._addApp(app);
-            }
-        } else {
-            let apps = this._appSystem.get_flattened_apps();
-            for (let i = 0; i < apps.length; i++) {
-                let app = apps[i];
-                this._addApp(app);
-            }
-        }
-
-        this._appsStale = false;
-        return false;
+        this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
     },
 
-    _setDefaultList : function() {
-        this._matchedItems = this._allItems;
-        this._matchedItemKeys = [];
-        for (let itemId in this._matchedItems) {
-            let app = this._allItems[itemId];
-            if (app.get_is_nodisplay())
-                continue;
-            this._matchedItemKeys.push(itemId);
-        }
-        this._matchedItemKeys.sort(Lang.bind(this, this._compareItems));
-    },
+    _redisplay: function() {
+        let apps = this._appSystem.get_flattened_apps().filter(function(app) {
+            return !app.get_is_nodisplay();
+        });
 
-    // Compares items associated with the item ids based on the alphabetical order
-    // of the item names.
-    // Returns an integer value indicating the result of the comparison.
-    _compareItems : function(itemIdA, itemIdB) {
-        let appA = this._allItems[itemIdA];
-        let appB = this._allItems[itemIdB];
-        return appA.get_name().localeCompare(appB.get_name());
+        this._appView.refresh(apps);
     },
 
-    // Checks if the item info can be a match for the search string by checking
-    // the name, description, execution command, and category for the application.
-    // Item info is expected to be Shell.AppInfo.
-    // Returns a boolean flag indicating if itemInfo is a match.
-    _isInfoMatching : function(itemInfo, search) {
-        // Don't show nodisplay items here
-        if (itemInfo.get_is_nodisplay())
-            return false;
+    toggle: function() {
+        this.emit('open-state-changed', !this.actor.visible);
 
-        if (search == null || search == '')
-            return true;
-
-        let fold = function(s) {
-            if (!s)
-                return s;
-            return GLib.utf8_casefold(GLib.utf8_normalize(s, -1,
-                                                          GLib.NormalizeMode.ALL), -1);
-        };
-        let name = fold(itemInfo.get_name());
-        if (name.indexOf(search) >= 0)
-            return true;
-
-        let description = fold(itemInfo.get_description());
-        if (description) {
-            if (description.indexOf(search) >= 0)
-                return true;
-        }
-
-        let exec = fold(itemInfo.get_executable());
-        if (exec == null) {
-            log("Missing an executable for " + itemInfo.name);
-        } else {
-            if (exec.indexOf(search) >= 0)
-                return true;
-        }
-
-        return false;
+        this.actor.visible = !this.actor.visible;
     },
 
-    // Creates an AppDisplayItem based on itemInfo, which is expected be an Shell.AppInfo object.
-    _createDisplayItem: function(itemInfo) {
-        return new AppDisplayItem(itemInfo);
+    close: function() {
+        if (!this.actor.visible)
+            return;
+        this.toggle();
     }
 };
 
-Signals.addSignalMethods(AppDisplay.prototype);
+Signals.addSignalMethods(AllAppDisplay.prototype);
 
 function BaseAppSearchProvider() {
     this._init();
@@ -414,6 +329,10 @@ AppWellIcon.prototype = {
         return false;
     },
 
+    getId: function() {
+        return this.app.get_id();
+    },
+
     popupMenu: function(activatingButton) {
         if (!this._menu) {
             this._menu = new AppIconMenu(this);
@@ -482,6 +401,7 @@ AppWellIcon.prototype = {
 
     _onActivate: function (event) {
         let running = this._getRunning();
+        this.emit('launching');
 
         if (!running) {
             this.app.launch();
@@ -826,12 +746,12 @@ function WellGrid() {
 
 WellGrid.prototype = {
     _init: function() {
-        this.actor = new St.Bin({ name: "dashAppWell" });
+        this.actor = new St.BoxLayout({ name: "dashAppWell", vertical: true });
         // Pulled from CSS, but hardcode some defaults here
         this._spacing = 0;
         this._item_size = 48;
         this._grid = new Shell.GenericContainer();
-        this.actor.set_child(this._grid);
+        this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
         this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
 
         this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
@@ -1021,7 +941,7 @@ AppWell.prototype = {
     // Draggable target interface
     acceptDrop : function(source, actor, x, y, time) {
         let app = null;
-        if (source instanceof AppDisplayItem) {
+        if (source instanceof AppWellIcon) {
             app = this._appSystem.get_app(source.getId());
         } else if (source instanceof Workspace.WindowClone) {
             app = this._tracker.get_window_app(source.metaWindow);
diff --git a/js/ui/dash.js b/js/ui/dash.js
index 38a8590..3278b11 100644
--- a/js/ui/dash.js
+++ b/js/ui/dash.js
@@ -50,8 +50,6 @@ SEARCH_BORDER_BOTTOM_COLOR.from_pixel(0x191919ff);
 const BROWSE_ACTIVATED_BG = new Clutter.Color();
 BROWSE_ACTIVATED_BG.from_pixel(0x303030f0);
 
-const APPS = "apps";
-const PREFS = "prefs";
 const DOCS = "docs";
 const PLACES = "places";
 
@@ -69,11 +67,7 @@ function _getIndexWrapped(index, increment, length) {
 }
 
 function _createDisplay(displayType, flags) {
-    if (displayType == APPS)
-        return new AppDisplay.AppDisplay(false, flags);
-    else if (displayType == PREFS)
-        return new AppDisplay.AppDisplay(true, flags);
-    else if (displayType == DOCS)
+    if (displayType == DOCS)
         return new DocDisplay.DocDisplay(flags);
     else if (displayType == PLACES)
         return new PlaceDisplay.PlaceDisplay(flags);
@@ -619,8 +613,8 @@ MoreLink.prototype = {
                                         reactive: true });
         this.pane = null;
 
-        let expander = new St.Bin({ style_class: "more-link-expander" });
-        this.actor.add(expander, { expand: true, y_fill: false });
+        this._expander = new St.Bin({ style_class: "more-link-expander" });
+        this.actor.add(this._expander, { expand: true, y_fill: false });
     },
 
     activate: function() {
@@ -635,6 +629,10 @@ MoreLink.prototype = {
     setPane: function (pane) {
         this._pane = pane;
         this._pane.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
+            if (!isOpen)
+                this._expander.style_class = 'more-link-expander';
+            else
+                this._expander.style_class = 'more-link-expander open';
         }));
     }
 }
@@ -884,13 +882,12 @@ Dash.prototype = {
         let appWell = new AppDisplay.AppWell();
         this._appsSection.content.add(appWell.actor, { expand: true });
 
-        this._moreAppsPane = null;
+        this._allApps = null;
         this._appsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
-            if (this._moreAppsPane == null) {
-                this._moreAppsPane = new ResultPane(this);
-                this._moreAppsPane.packResults(APPS);
-                this._addPane(this._moreAppsPane);
-                link.setPane(this._moreAppsPane);
+            if (this._allApps == null) {
+                this._allApps = new AppDisplay.AllAppDisplay();
+                this._addPane(this._allApps);
+                link.setPane(this._allApps);
            }
         }));
 
diff --git a/js/ui/overview.js b/js/ui/overview.js
index 50edd9c..4db84d1 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -234,8 +234,7 @@ Overview.prototype = {
         this._group.add_actor(this._dash.actor);
 
         // Container to hold popup pane chrome.
-        this._paneContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
-                                             spacing: 6 });
+        this._paneContainer = new St.BoxLayout({ style_class: 'overview-pane' });
         // Note here we explicitly don't set the paneContainer to be reactive yet; that's done
         // inside the notify::visible handler on panes.
         this._paneContainer.connect('button-release-event', Lang.bind(this, function(background) {
@@ -245,7 +244,7 @@ Overview.prototype = {
         this._group.add_actor(this._paneContainer);
 
         this._transparentBackground.lower_bottom();
-        this._paneContainer.lower_bottom();
+        this._paneContainer.hide();
 
         this._coverPane.lower_bottom();
 
@@ -362,12 +361,10 @@ Overview.prototype = {
         this._transparentBackground.set_size(primary.width - this._paneContainer.x,
                                              this._paneContainer.height);
 
-        if (this._activeDisplayPane != null)
-            this._activeDisplayPane.actor.width = displayGridColumnWidth * 2;
     },
 
     addPane: function (pane) {
-        this._paneContainer.append(pane.actor, Big.BoxPackFlags.NONE);
+        this._paneContainer.add(pane.actor, { expand: true, y_fill: false, y_align: St.Align.START });
         // When a pane is displayed, we raise the transparent background to the top
         // and connect to button-release-event on it, then raise the pane above that.
         // The idea here is that clicking anywhere outside the pane should close it.
@@ -375,10 +372,10 @@ Overview.prototype = {
         let backgroundEventId = null;
         pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
             if (isOpen) {
-                pane.actor.width = displayGridColumnWidth * 2;
                 this._activeDisplayPane = pane;
                 this._transparentBackground.raise_top();
                 this._paneContainer.raise_top();
+                this._paneContainer.show();
                 if (backgroundEventId != null)
                     this._transparentBackground.disconnect(backgroundEventId);
                 backgroundEventId = this._transparentBackground.connect('button-release-event', Lang.bind(this, function () {
@@ -393,7 +390,7 @@ Overview.prototype = {
                     backgroundEventId = null;
                 }
                 this._transparentBackground.lower_bottom();
-                this._paneContainer.lower_bottom();
+                this._paneContainer.hide();
                 this._workspaces.actor.opacity = 255;
             }
         }));



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