diff --git a/js/ui/dash.js b/js/ui/dash.js
index edd463e..8b1f605 100644
--- a/js/ui/dash.js
+++ b/js/ui/dash.js
@@ -155,7 +155,7 @@ ResultArea.prototype = {
         this.resultsContainer.append(this.display.actor, Big.BoxPackFlags.EXPAND);
 
         this.controlBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER });
-        this.controlBox.append(this.display.displayControl, Big.BoxPackFlags.NONE);
+        this.controlBox.append(this.display.displayControl.actor, Big.BoxPackFlags.NONE);
         this.actor.append(this.controlBox, Big.BoxPackFlags.NONE);
 
         this.display.load();
diff --git a/js/ui/genericDisplay.js b/js/ui/genericDisplay.js
index 6f13477..a87df87 100644
--- a/js/ui/genericDisplay.js
+++ b/js/ui/genericDisplay.js
@@ -343,13 +343,6 @@ GenericDisplay.prototype = {
         this._list = new Shell.OverflowList({ spacing: 6.0,
                                               item_height: ITEM_DISPLAY_HEIGHT });
 
-        this._list.connect('notify::n-pages', Lang.bind(this, function () {
-            this._updateDisplayControl(true);
-        }));
-        this._list.connect('notify::page', Lang.bind(this, function () {
-            this._updateDisplayControl(false);
-        }));
-
         // map<itemId, Object> where Object represents the item info
         this._allItems = {};
         // an array of itemIds of items that match the current request
@@ -363,9 +356,13 @@ GenericDisplay.prototype = {
         // but we also expose a .displayControl actor which is separate.
         // See also getNavigationArea.
         this.actor = this._list;
-        this.displayControl = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
-                                            spacing: 12,
-                                            orientation: Big.BoxOrientation.HORIZONTAL});
+        this.displayControl = new PagingControl(this._list, this._displayPage);
+        this._list.connect('notify::n-pages', Lang.bind(this, function () {
+            this.displayControl.update()
+        }));
+        this._list.connect('notify::page', Lang.bind(this, function () {
+            this.displayControl.update()
+        }));
     },
 
     //// Public methods ////
@@ -471,13 +468,8 @@ GenericDisplay.prototype = {
     /*
      * Displays items that match the current request and should show up on the current page.
      * Updates the display control to reflect the matched items set and the page selected.
-     *
-     * resetDisplayControl - indicates if the display control should be re-created because 
-     *                       the results or the space allocated for them changed. If it's false,
-     *                       the existing display control is used and only the page links are
-     *                       updated to reflect the current page selection.
      */
-    _displayMatchedItems: function(resetDisplayControl) {
+    _displayMatchedItems: function() {
         // When generating a new list to display, we first remove all the old
         // displayed items which will unset the selection. So we need 
         // to keep a flag which indicates if this display had the selection.
@@ -603,7 +595,7 @@ GenericDisplay.prototype = {
         if (resetPage)
             this._list.page = 0;
 
-        this._displayMatchedItems(true);
+        this._displayMatchedItems();
 
         this.emit('redisplayed');
     },
@@ -699,50 +691,6 @@ GenericDisplay.prototype = {
         this._list.page = pageNumber;
     },
 
-    /*
-     * Updates the display control to reflect the matched items set and the page selected.
-     *
-     * resetDisplayControl - indicates if the display control should be re-created because 
-     *                       the results or the space allocated for them changed. If it's false,
-     *                       the existing display control is used and only the page links are
-     *                       updated to reflect the current page selection.
-     */
-    _updateDisplayControl: function(resetDisplayControl) {
-        if (resetDisplayControl) {
-            this._selectedIndex = -1;
-            this.displayControl.remove_all();
-            let nPages = this._list.n_pages;
-            let pageNumber = this._list.page;
-            for (let i = 0; i < nPages; i++) {
-                let pageControl = new Link.Link({ color: (i == pageNumber) ? DISPLAY_CONTROL_SELECTED_COLOR : ITEM_DISPLAY_DESCRIPTION_COLOR,
-                                                  font_name: "Sans Bold 16px",
-                                                  text: (i+1) + "",
-                                                  reactive: (i == pageNumber) ? false : true});
-                this.displayControl.append(pageControl.actor, Big.BoxPackFlags.NONE);
-
-                // we use pageNumberLocalScope to get the page number right in the callback function
-                let pageNumberLocalScope = i;
-                pageControl.connect('clicked',
-                                    Lang.bind(this,
-                                              function(o, event) {
-                                                  this._displayPage(pageNumberLocalScope);
-                                              }));
-            }
-        } else {
-            let pageControlActors = this.displayControl.get_children();
-            for (let i = 0; i < pageControlActors.length; i++) {
-                let pageControlActor = pageControlActors[i];
-                if (i == this._list.page) {
-                    pageControlActor.color =  DISPLAY_CONTROL_SELECTED_COLOR;
-                    pageControlActor.reactive = false;
-                } else {
-                    pageControlActor.color =  ITEM_DISPLAY_DESCRIPTION_COLOR;
-                    pageControlActor.reactive = true;
-                }
-            } 
-        }
-    },
-
     // Returns a display item based on its index in the ordering of the
     // display children.
     _findDisplayedByIndex: function(index) {
@@ -791,3 +739,226 @@ GenericDisplay.prototype = {
 };
 
 Signals.addSignalMethods(GenericDisplay.prototype);
+
+function PagingControl(list, callback) {
+    this._init(list, callback);
+}
+
+PagingControl.prototype = {
+    _init : function(list, callback) {
+        this.actor = new Shell.GenericContainer();
+        this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
+        this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
+        this.actor.connect('allocate', Lang.bind(this, this._allocate));
+
+        this._list = list;
+        this._callback = callback;
+        this._pageControls = [];
+        this._numPages = 0;
+        this._currentPage = 0;
+        this._spacing = 12;
+        this._goFirst = this._createActor(0, "<<");
+        this._goLast = this._createActor(-1, ">>");
+        this.actor.add_actor(this._goFirst.actor);
+        this.actor.add_actor(this._goLast.actor);
+        this.update();
+    },
+
+    _createActor : function(pageNumber, text) {
+        let pageControl = new Link.Link({ color: ITEM_DISPLAY_DESCRIPTION_COLOR,
+                                          font_name: "Sans Bold 16px",
+                                          text: text,
+                                          reactive: true});
+        pageControl.connect('clicked',
+                            Lang.bind(this, function(o, event) {
+                                                this._callback((pageNumber >= 0) ? pageNumber : this._numPages);
+                                            }));
+        return pageControl;
+    },
+
+    _updateActors : function() {
+        let numPages = this._list.n_pages;
+        if (numPages < this._numPages) {
+            this._pageControls.slice(numPages, this._numPages - numPages);
+            for each (actor in this.actor.get_children().slice(numPages + 2))
+                actor.destroy();
+        } else if (numPages > this._numPages)
+            for (let i = this._numPages + 1; i <= numPages; i++) {
+                let pageNumber = i; // local scope
+                let page = this._createActor(pageNumber - 1, pageNumber + "")
+                this._pageControls.push(page);
+                this.actor.add_actor(page.actor);
+            }
+        this._numPages = numPages;
+    },
+
+    _getPreferredWidth: function (grid, forHeight, alloc) {
+        if (this._numPages < 2) {
+            alloc.min_size = 0;
+            alloc.natural_size = 0;
+            return;
+        }
+
+        let minWidth = 0, naturalWidth = 0;
+        let children = this.actor.get_children();
+        for (let i = 0; i < children.length; i++) {
+            let [currentMinWidth, currentNaturalWidth] = children[i].get_preferred_width(-1);
+            let spacing = (i != 0) ? this._spacing : 0;
+            // We always display at least 4 items (eg. "<< 5 6 >>").
+            if (i <= 4)
+                minWidth += currentMinWidth + spacing;
+            naturalWidth += currentNaturalWidth + spacing;
+        }
+
+        alloc.min_size = minWidth;
+        alloc.natural_size = naturalWidth;
+    },
+
+    _getPreferredHeight: function (grid, forWidth, alloc) {
+        if (this._numPages < 2) {
+            alloc.min_size = 0;
+            alloc.natural_size = 0;
+            return;
+        }
+
+        let minHeight = 0, naturalHeight = 0;
+        let children = this.actor.get_children();
+        for (let i = 0; i <  children.length; i++) {
+            let [currentMinHeight, currentNaturalHeight] = children[i].get_preferred_height(-1);
+            if (currentMinHeight > minHeight)
+                minHeight = currentMinHeight;
+            if (currentNaturalHeight > naturalHeight)
+                naturalHeight = currentNaturalHeight;
+        }
+
+        alloc.min_size = minHeight;
+        alloc.natural_size = naturalHeight;
+    },
+
+    _actor_size: function (actor) {
+        // Returns naturalWidth, naturalHeight
+        return actor.get_preferred_size().slice(2, 4)
+    },
+
+    // Adds the given value to the given array (destination), appending
+    // it to the back if it's bigger than the last entry in it and
+    // prepending it otherwise
+    _put_into: function (destination, value) {
+        if (destination.length && value[0] > destination[destination.length - 1][0])
+            destination.push(value);
+        else
+            destination.splice(0, 0, value);
+    },
+
+    // blah blah blah
+    // bla blah
+    _allocate: function (grid, box, flags) {
+        let availWidth = box.x2 - box.x1;
+        let availHeight = box.y2 - box.y1;
+        let children = this.actor.get_children(); // [goFirst, goLast, pageNumbers...]
+        let goFirstWidth = this._actor_size(children[0])[0];
+        let goLastWidth = this._actor_size(children[1])[0];
+        let firstPage = 2;
+        let lastPage = children.length - 1;
+        let width, height;
+
+        let visiblePages = [];
+        let offset = 1;
+        let remainingPagesInBothDirections = true;
+        // Reserve some space for the "<<" and ">>" arrows.
+        let usedWidth = goFirstWidth + goLastWidth + this._spacing * 2;
+        // Ensure the page isn't negative, and skip goFirst and goLast
+        let i = Math.max(firstPage, this._currentPage + firstPage), start = i, j;
+
+        // Start from the selected page and add more pages, one to the right
+        // and one to the left each time, until there's no more space left
+        [width, height] = this._actor_size(children[i]);
+        let firstOrLastPage = (i == firstPage || i == lastPage);
+        while ((usedWidth + width) <= availWidth) {
+            // Append or prepend item to the list of visible pages
+            this._put_into(visiblePages, [i, width, height]);
+            usedWidth += width + this._spacing;
+
+            // From now one we can only move in a single direction,
+            // no remaining pages at the other side
+            j = i;
+            if (i == firstPage || i == lastPage) {
+                if (i != start || i == lastPage) {
+                    i += -1 * offset;
+                }
+                offset = (j == firstPage) ? 1 : -1;
+                if (!remainingPagesInBothDirections)
+                    break;
+                remainingPagesInBothDirections = false;
+            } else if (i != start && remainingPagesInBothDirections) {
+                // Now take a page from the other side
+                offset = -1 * (offset + 1);
+            }
+            if (i == j || j != start)
+                i += offset;
+
+            // Load the data for the next iteration and the while condition
+            [width, height] = this._actor_size(children[i]);
+        }
+
+        if (visiblePages.length < 1)
+            return;
+
+        let firstVisiblePage = visiblePages[0][0];
+        let lastVisiblePage = visiblePages[visiblePages.length - 1][0];
+        if (firstVisiblePage > 2) {
+            // Add "<<"
+            [width, height] = this._actor_size(children[0]);
+            visiblePages.splice(0, 0, [0, width, height]);
+        }
+        if (lastVisiblePage < (children.length - 1)) {
+            // Add ">>"
+            [width, height] = this._actor_size(children[1]);
+            visiblePages.push([1, width, height]);
+        }
+
+        /*
+        x = " .. ";
+        for (let i = 0; i < visiblePages.length; i++)
+            x += "["+visiblePages[i]+"] ";
+        log (x);
+        */
+
+        for (let i = 0; i < children.length; i++) {
+            children[i].set_opacity(0x00);
+            children[i].set_reactive(false);
+        }
+
+        let x = box.x1;
+        let y = box.y1;
+        for (let i in visiblePages) {
+            let [j, width, height] = visiblePages[i];
+            children[j].set_opacity(0xff);
+            if ((j - 2) != this._currentPage)
+                children[j].set_reactive(true);
+            let childBox = new Clutter.ActorBox();
+            childBox.x1 = x;
+            childBox.y1 = y;
+            childBox.x2 = childBox.x1 + width;
+            childBox.y2 = childBox.y1 + height;
+            children[j].allocate(childBox, flags);
+            x = childBox.x2 + this._spacing;
+        }
+     },
+
+    update : function() {
+        this._updateActors();
+        let pageNumber = this._list.page + 0;
+        if (this._currentPage < this._pageControls.length) {
+            let previousPage = this._pageControls[this._currentPage].actor;
+            previousPage.color = ITEM_DISPLAY_DESCRIPTION_COLOR;
+        }
+        let currentPage = this._pageControls[pageNumber].actor;
+        currentPage.color = DISPLAY_CONTROL_SELECTED_COLOR;
+
+        this._currentPage = pageNumber;
+        this.actor.queue_relayout();
+    }
+};
+
+Signals.addSignalMethods(PagingControl.prototype);
