Home | History | Annotate | Download | only in chromeos
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/wm_overview_controller.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/memory/linked_ptr.h"
     11 #include "chrome/browser/browser_process.h"
     12 #include "chrome/browser/chromeos/wm_ipc.h"
     13 #include "chrome/browser/chromeos/wm_overview_favicon.h"
     14 #include "chrome/browser/chromeos/wm_overview_snapshot.h"
     15 #include "chrome/browser/chromeos/wm_overview_title.h"
     16 #include "chrome/browser/tab_contents/thumbnail_generator.h"
     17 #include "chrome/browser/tabs/tab_strip_model.h"
     18 #include "chrome/browser/ui/browser.h"
     19 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     20 #include "chrome/browser/ui/views/frame/browser_view.h"
     21 #include "content/browser/renderer_host/render_view_host.h"
     22 #include "content/browser/renderer_host/render_widget_host.h"
     23 #include "content/browser/renderer_host/render_widget_host_view.h"
     24 #include "content/browser/tab_contents/tab_contents.h"
     25 #include "content/browser/tab_contents/tab_contents_view.h"
     26 #include "content/common/notification_service.h"
     27 #include "views/widget/root_view.h"
     28 #include "views/widget/widget_gtk.h"
     29 #include "views/window/window.h"
     30 
     31 using std::vector;
     32 
     33 #if !defined(OS_CHROMEOS)
     34 #error This file is only meant to be compiled for ChromeOS
     35 #endif
     36 
     37 namespace chromeos {
     38 
     39 // Use this timer to delay consecutive snapshots during the updating process.
     40 // We will start the timer upon successfully retrieving a new snapshot, or if
     41 // for some reason the current snapshot is still pending (while Chrome is
     42 // still loading the page.)
     43 static const int kDelayTimeMs = 10;
     44 
     45 // This is the size of the web page when we lay it out for a snapshot.
     46 static const int kSnapshotWebPageWidth = 1024;
     47 static const int kSnapshotWebPageHeight = 1280;
     48 static const double kSnapshotWebPageRatio =
     49     static_cast<double>(kSnapshotWebPageWidth) / kSnapshotWebPageHeight;
     50 
     51 // This is the maximum percentage of the original browser client area
     52 // that a snapshot can take up.
     53 static const double kSnapshotMaxSizeRatio = 0.77;
     54 
     55 // This is the height of the title in pixels.
     56 static const int kTitleHeight = 32;
     57 
     58 // The number of additional padding pixels to remove from the title width.
     59 static const int kFaviconPadding = 5;
     60 
     61 class BrowserListener : public TabStripModelObserver {
     62  public:
     63   BrowserListener(Browser* browser, WmOverviewController* parent);
     64   ~BrowserListener();
     65 
     66   // Begin TabStripModelObserver methods
     67   virtual void TabInsertedAt(TabContentsWrapper* contents,
     68                              int index,
     69                              bool foreground);
     70   virtual void TabClosingAt(TabStripModel* tab_strip_model,
     71                             TabContentsWrapper* contents,
     72                             int index) {}
     73   virtual void TabDetachedAt(TabContentsWrapper* contents, int index);
     74   virtual void TabMoved(TabContentsWrapper* contents,
     75                         int from_index,
     76                         int to_index);
     77   virtual void TabChangedAt(TabContentsWrapper* contents, int index,
     78                             TabStripModelObserver::TabChangeType change_type);
     79   virtual void TabStripEmpty();
     80   virtual void TabDeselected(TabContentsWrapper* contents) {}
     81   virtual void TabSelectedAt(TabContentsWrapper* old_contents,
     82                              TabContentsWrapper* new_contents,
     83                              int index,
     84                              bool user_gesture);
     85   // End TabStripModelObserver methods
     86 
     87   // Returns the number of tabs in this child.
     88   int count() const { return browser_->tabstrip_model()->count(); }
     89 
     90   // Returns the browser that this child gets its data from.
     91   Browser* browser() const { return browser_; }
     92 
     93   // Removes all the snapshots and re-populates them from the browser.
     94   void RecreateSnapshots();
     95 
     96   // Mark the given snapshot as dirty, and start the delay timer.
     97   void MarkSnapshotAsDirty(int index);
     98 
     99   // Updates the selected index and tab count on the toplevel window.
    100   void UpdateSelectedIndex(int index);
    101 
    102   // Update the first "dirty" snapshot, which is ordered after (excluding)
    103   // the snapshot whose index is given by |start_from|; When |start_from| is
    104   // -1, search start at the begining of the list.
    105   // Return the index of the snapshot which is actually updated; -1 if there
    106   // are no more tab contents (after |start_from|) to configure on this
    107   // listener.
    108   int ConfigureNextUnconfiguredSnapshot(int start_from);
    109 
    110   // Saves the currently selected tab.
    111   void SaveCurrentTab() { original_selected_tab_ = browser_->active_index(); }
    112 
    113   // Reverts the selected browser tab to the tab that was selected
    114   // when This BrowserListener was created, or the last time
    115   // SaveCurrentTab was called.
    116   void RestoreOriginalSelectedTab();
    117 
    118   // Selects the tab at the given index.
    119   void SelectTab(int index, uint32 timestamp);
    120 
    121   // Shows any snapshots that are not visible.
    122   void ShowSnapshots();
    123 
    124   // Callback for |AskForSnapshot|, start delay timer for next round.
    125   void OnSnapshotReady(const SkBitmap& sk_bitmap);
    126 
    127   // Returns the tab contents from the tab model for this child at index.
    128   TabContents* GetTabContentsAt(int index) const  {
    129     return browser_->tabstrip_model()->GetTabContentsAt(index)->tab_contents();
    130   }
    131 
    132  private:
    133   // Calculate the size of a cell based on the browser window's size.
    134   gfx::Size CalculateCellSize();
    135 
    136   // Configures a cell from the tab contents.
    137   void ConfigureCell(WmOverviewSnapshot* cell, TabContents* contents);
    138 
    139   // Configures a cell from the model.
    140   void ConfigureCell(WmOverviewSnapshot* cell, int index) {
    141     ConfigureCell(cell, GetTabContentsAt(index));
    142   }
    143 
    144   // Inserts a new snapshot, initialized from the model, at the given
    145   // index, and renumbers any following snapshots.
    146   void InsertSnapshot(int index);
    147 
    148   // Removes the snapshot at index.
    149   void ClearSnapshot(int index);
    150 
    151   // Renumbers the index atom in the snapshots starting at the given
    152   // index.
    153   void RenumberSnapshots(int start_index);
    154 
    155   Browser* browser_;  // Not owned
    156   WmOverviewController* controller_;  // Not owned
    157 
    158   // Which renderer host we are working on.
    159   RenderWidgetHost* current_renderer_host_; // Not owned
    160 
    161   // Widgets containing snapshot images for this browser.  Note that
    162   // these are all subclasses of WidgetGtk, and they are all added to
    163   // parents, so they will be deleted by the parents when they are
    164   // closed.
    165   struct SnapshotNode {
    166     WmOverviewSnapshot* snapshot;  // Not owned
    167     WmOverviewTitle* title;  // Not owned
    168     WmOverviewFavicon* favicon;  // Not owned
    169   };
    170   typedef std::vector<SnapshotNode> SnapshotVector;
    171   SnapshotVector snapshots_;
    172 
    173   // Non-zero if we are currently setting the tab from within SelectTab.
    174   // This is used to make sure we use the right timestamp when sending
    175   // property changes that originated from the window manager.
    176   uint32 select_tab_timestamp_;
    177 
    178   // The tab selected the last time SaveCurrentTab is called.
    179   int original_selected_tab_;
    180 
    181   DISALLOW_COPY_AND_ASSIGN(BrowserListener);
    182 };
    183 
    184 BrowserListener::BrowserListener(Browser* browser,
    185                                  WmOverviewController* controller)
    186     : browser_(browser),
    187       controller_(controller),
    188       current_renderer_host_(NULL),
    189       select_tab_timestamp_(0),
    190       original_selected_tab_(-1) {
    191   CHECK(browser_);
    192   CHECK(controller_);
    193 
    194   browser_->tabstrip_model()->AddObserver(this);
    195 
    196   // This browser didn't already exist, and so we haven't been
    197   // watching it for tab insertions, so we need to create the
    198   // snapshots associated with it.
    199   RecreateSnapshots();
    200 }
    201 
    202 BrowserListener::~BrowserListener() {
    203   browser_->tabstrip_model()->RemoveObserver(this);
    204 }
    205 
    206 void BrowserListener::TabInsertedAt(TabContentsWrapper* contents,
    207                                     int index,
    208                                     bool foreground) {
    209   InsertSnapshot(index);
    210   RenumberSnapshots(index);
    211   UpdateSelectedIndex(browser_->active_index());
    212 }
    213 
    214 void BrowserListener::TabDetachedAt(TabContentsWrapper* contents, int index) {
    215   ClearSnapshot(index);
    216   UpdateSelectedIndex(browser_->active_index());
    217   RenumberSnapshots(index);
    218 }
    219 
    220 void BrowserListener::TabMoved(TabContentsWrapper* contents,
    221                                int from_index,
    222                                int to_index) {
    223   // Need to reorder tab in the snapshots list, and reset the window
    224   // type atom on the affected snapshots (the one moved, and all the
    225   // ones after it), so that their indices are correct.
    226   SnapshotNode node = snapshots_[from_index];
    227   snapshots_.erase(snapshots_.begin() + from_index);
    228   snapshots_.insert(snapshots_.begin() + to_index, node);
    229 
    230   RenumberSnapshots(std::min(to_index, from_index));
    231   UpdateSelectedIndex(browser_->active_index());
    232 }
    233 
    234 void BrowserListener::TabChangedAt(
    235     TabContentsWrapper* contents,
    236     int index,
    237     TabStripModelObserver::TabChangeType change_type) {
    238   if (change_type != TabStripModelObserver::LOADING_ONLY) {
    239     snapshots_[index].title->SetTitle(contents->tab_contents()->GetTitle());
    240     snapshots_[index].title->SetUrl(contents->tab_contents()->GetURL());
    241     snapshots_[index].favicon->SetFavicon(
    242         contents->tab_contents()->GetFavicon());
    243     if (change_type != TabStripModelObserver::TITLE_NOT_LOADING)
    244       MarkSnapshotAsDirty(index);
    245   }
    246 }
    247 
    248 void BrowserListener::TabStripEmpty() {
    249   snapshots_.clear();
    250 }
    251 
    252 void BrowserListener::TabSelectedAt(TabContentsWrapper* old_contents,
    253                                     TabContentsWrapper* new_contents,
    254                                     int index,
    255                                     bool user_gesture) {
    256   if (old_contents == new_contents)
    257     return;
    258 
    259   UpdateSelectedIndex(index);
    260 }
    261 
    262 void BrowserListener::MarkSnapshotAsDirty(int index) {
    263   snapshots_[index].snapshot->reload_snapshot();
    264   controller_->UpdateSnapshots();
    265 }
    266 
    267 void BrowserListener::RecreateSnapshots() {
    268   snapshots_.clear();
    269 
    270   for (int i = 0; i < count(); ++i)
    271     InsertSnapshot(i);
    272 
    273   RenumberSnapshots(0);
    274 }
    275 
    276 void BrowserListener::UpdateSelectedIndex(int index) {
    277   WmIpcWindowType type = WmIpc::instance()->GetWindowType(
    278       GTK_WIDGET(browser_->window()->GetNativeHandle()), NULL);
    279   // Make sure we only operate on toplevel windows.
    280   if (type == WM_IPC_WINDOW_CHROME_TOPLEVEL) {
    281     std::vector<int> params;
    282     params.push_back(browser_->tab_count());
    283     params.push_back(index);
    284     params.push_back(select_tab_timestamp_ ? select_tab_timestamp_ :
    285                      gtk_get_current_event_time());
    286     WmIpc::instance()->SetWindowType(
    287         GTK_WIDGET(browser_->window()->GetNativeHandle()),
    288         WM_IPC_WINDOW_CHROME_TOPLEVEL,
    289         &params);
    290   }
    291 }
    292 
    293 int BrowserListener::ConfigureNextUnconfiguredSnapshot(int start_from) {
    294   for (SnapshotVector::size_type i = start_from + 1;
    295       i < snapshots_.size(); ++i) {
    296     WmOverviewSnapshot* cell = snapshots_[i].snapshot;
    297     if (!cell->configured_snapshot()) {
    298       ConfigureCell(cell, i);
    299       return i;
    300     }
    301   }
    302   return -1;
    303 }
    304 
    305 void BrowserListener::RestoreOriginalSelectedTab() {
    306   if (original_selected_tab_ >= 0) {
    307     browser_->ActivateTabAt(original_selected_tab_, false);
    308     UpdateSelectedIndex(browser_->active_index());
    309   }
    310 }
    311 
    312 void BrowserListener::ShowSnapshots() {
    313   for (SnapshotVector::size_type i = 0; i < snapshots_.size(); ++i) {
    314     const SnapshotNode& node = snapshots_[i];
    315     if (!node.snapshot->IsVisible())
    316       node.snapshot->Show();
    317     if (!snapshots_[i].title->IsVisible())
    318       node.title->Show();
    319     if (!snapshots_[i].favicon->IsVisible())
    320       node.favicon->Show();
    321   }
    322 }
    323 
    324 void BrowserListener::SelectTab(int index, uint32 timestamp) {
    325   // Ignore requests to switch to non-existent tabs (the window manager gets
    326   // notified asynchronously about the number of tabs in each window, so there's
    327   // no guarantee that the messages that it sends us will make sense).
    328   if (index < 0 || index >= browser_->tab_count())
    329     return;
    330 
    331   uint32 old_value = select_tab_timestamp_;
    332   select_tab_timestamp_ = timestamp;
    333   browser_->ActivateTabAt(index, true);
    334   select_tab_timestamp_ = old_value;
    335 }
    336 
    337 gfx::Size BrowserListener::CalculateCellSize() {
    338   // Make the page size and the cell size a fixed size for overview
    339   // mode.  The cell size is calculated based on the desired maximum
    340   // size on the screen, so it's related to the width and height of
    341   // the browser client area.  In this way, when this snapshot gets
    342   // to the window manager, it will already have the correct size,
    343   // and will be scaled by 1.0, meaning that it won't be resampled
    344   // and will not be blurry.
    345   gfx::Rect bounds = static_cast<BrowserView*>(browser_->window())->
    346                      GetClientAreaBounds();
    347   const gfx::Size max_size = gfx::Size(
    348       bounds.width() * kSnapshotMaxSizeRatio,
    349       bounds.height() * kSnapshotMaxSizeRatio);
    350   const double max_size_ratio = static_cast<double>(max_size.width()) /
    351                                 max_size.height();
    352   gfx::Size cell_size;
    353   if (kSnapshotWebPageRatio > max_size_ratio) {
    354     const double scale_factor =
    355         static_cast<double>(max_size.width())/ kSnapshotWebPageWidth;
    356     cell_size = gfx::Size(max_size.width(),
    357                           kSnapshotWebPageHeight * scale_factor + 0.5);
    358   } else {
    359     const double scale_factor =
    360         static_cast<double>(max_size.height())/ kSnapshotWebPageHeight;
    361     cell_size = gfx::Size(kSnapshotWebPageWidth * scale_factor + 0.5,
    362                           max_size.height());
    363   }
    364   return cell_size;
    365 }
    366 
    367 void BrowserListener::OnSnapshotReady(const SkBitmap& sk_bitmap) {
    368   for (int i = 0; i < count(); i++) {
    369     RenderWidgetHostView* view =
    370         GetTabContentsAt(i)->GetRenderWidgetHostView();
    371     if (view && view->GetRenderWidgetHost() == current_renderer_host_) {
    372       snapshots_[i].snapshot->SetImage(sk_bitmap);
    373       current_renderer_host_ = NULL;
    374 
    375       // Start timer for next round of snapshot updating.
    376       controller_->StartDelayTimer();
    377       return;
    378     }
    379   }
    380   DCHECK(current_renderer_host_ == NULL);
    381 }
    382 
    383 void BrowserListener::ConfigureCell(WmOverviewSnapshot* cell,
    384                                     TabContents* contents) {
    385   if (contents) {
    386     ThumbnailGenerator* generator =
    387         g_browser_process->GetThumbnailGenerator();
    388     // TODO: Make sure that if the cell gets deleted before the
    389     // callback is called that it sticks around until it gets
    390     // called.  (some kind of "in flight" list that uses linked_ptr
    391     // to make sure they don't actually get deleted?)  Also, make
    392     // sure that any request for a thumbnail eventually returns
    393     // (even if it has bogus data), so we don't leak orphaned cells,
    394     // which could happen if a tab is closed while it is being
    395     // rendered.
    396     ThumbnailGenerator::ThumbnailReadyCallback* callback =
    397         NewCallback(this, &BrowserListener::OnSnapshotReady);
    398 
    399     current_renderer_host_ = contents->render_view_host();
    400     generator->AskForSnapshot(contents->render_view_host(),
    401                               false,
    402                               callback,
    403                               gfx::Size(kSnapshotWebPageWidth,
    404                                         kSnapshotWebPageHeight),
    405                               CalculateCellSize());
    406   } else {
    407     // This happens because the contents haven't been loaded yet.
    408 
    409     // Make sure we set the snapshot image to something, otherwise
    410     // configured_snapshot remains false and
    411     // ConfigureNextUnconfiguredSnapshot would get stuck.
    412     current_renderer_host_ = NULL;
    413     cell->SetImage(SkBitmap());
    414     cell->reload_snapshot();
    415     controller_->StartDelayTimer();
    416   }
    417 }
    418 
    419 void BrowserListener::InsertSnapshot(int index) {
    420   SnapshotNode node;
    421   node.snapshot = new WmOverviewSnapshot;
    422   gfx::Size cell_size = CalculateCellSize();
    423   node.snapshot->Init(cell_size, browser_, index);
    424 
    425   node.favicon = new WmOverviewFavicon;
    426   node.favicon->Init(node.snapshot);
    427   node.favicon->SetFavicon(browser_->GetTabContentsAt(index)->GetFavicon());
    428 
    429   node.title = new WmOverviewTitle;
    430   node.title->Init(gfx::Size(std::max(0, cell_size.width() -
    431                                       WmOverviewFavicon::kIconSize -
    432                                       kFaviconPadding),
    433                              kTitleHeight), node.snapshot);
    434   node.title->SetTitle(browser_->GetTabContentsAt(index)->GetTitle());
    435 
    436   snapshots_.insert(snapshots_.begin() + index, node);
    437   node.snapshot->reload_snapshot();
    438   controller_->UpdateSnapshots();
    439 }
    440 
    441 // Removes the snapshot at index.
    442 void BrowserListener::ClearSnapshot(int index) {
    443   snapshots_[index].snapshot->CloseNow();
    444   snapshots_[index].title->CloseNow();
    445   snapshots_[index].favicon->CloseNow();
    446   snapshots_.erase(snapshots_.begin() + index);
    447 }
    448 
    449 void BrowserListener::RenumberSnapshots(int start_index) {
    450   for (SnapshotVector::size_type i = start_index; i < snapshots_.size(); ++i) {
    451     if (snapshots_[i].snapshot->index() != static_cast<int>(i))
    452       snapshots_[i].snapshot->UpdateIndex(browser_, i);
    453   }
    454 }
    455 
    456 ///////////////////////////////////
    457 // WmOverviewController methods
    458 
    459 // static
    460 WmOverviewController* WmOverviewController::GetInstance() {
    461   static WmOverviewController* instance = NULL;
    462   if (!instance) {
    463     instance = Singleton<WmOverviewController>::get();
    464   }
    465   return instance;
    466 }
    467 
    468 WmOverviewController::WmOverviewController()
    469     : layout_mode_(ACTIVE_MODE),
    470       updating_snapshots_(false),
    471       browser_listener_index_(0),
    472       tab_contents_index_(-1) {
    473   AddAllBrowsers();
    474 
    475   if (registrar_.IsEmpty()) {
    476     // Make sure we get notifications for when the tab contents are
    477     // connected, so we know when a new browser has been created.
    478     registrar_.Add(this,
    479                    NotificationType::TAB_CONTENTS_CONNECTED,
    480                    NotificationService::AllSources());
    481 
    482     // Ask for notification when the snapshot source image has changed
    483     // and needs to be refreshed.
    484     registrar_.Add(this,
    485                    NotificationType::THUMBNAIL_GENERATOR_SNAPSHOT_CHANGED,
    486                    NotificationService::AllSources());
    487   }
    488 
    489   BrowserList::AddObserver(this);
    490   WmMessageListener::GetInstance()->AddObserver(this);
    491 }
    492 
    493 WmOverviewController::~WmOverviewController() {
    494   WmMessageListener::GetInstance()->RemoveObserver(this);
    495   BrowserList::RemoveObserver(this);
    496   listeners_.clear();
    497 }
    498 
    499 void WmOverviewController::Observe(NotificationType type,
    500                                    const NotificationSource& source,
    501                                    const NotificationDetails& details) {
    502   switch (type.value) {
    503     // Now that the tab contents are ready, we create the listeners
    504     // and snapshots for any new browsers out there.  This actually
    505     // results in us traversing the list of browsers more often than
    506     // necessary (whenever a tab is connected, as opposed to only when
    507     // a new browser is created), but other notifications aren't
    508     // sufficient to know when the first tab of a new browser has its
    509     // dimensions set.  The implementation of AddAllBrowsers avoids
    510     // doing anything to already-existing browsers, so it's not a huge
    511     // problem, but still, it would be nice if there were a more
    512     // appropriate (browser-level) notification.
    513     case NotificationType::TAB_CONTENTS_CONNECTED:
    514       AddAllBrowsers();
    515       break;
    516 
    517     case NotificationType::THUMBNAIL_GENERATOR_SNAPSHOT_CHANGED: {
    518       // It's OK to do this in active mode too -- nothing will happen
    519       // except invalidation of the snapshot, because the delay timer
    520       // won't start until we're in overview mode.
    521       RenderWidgetHost* renderer = Details<RenderViewHost>(details).ptr();
    522       SnapshotImageChanged(renderer);
    523       break;
    524     }
    525     default:
    526       // Do nothing.
    527       break;
    528   }
    529 }
    530 
    531 void WmOverviewController::SnapshotImageChanged(RenderWidgetHost* renderer) {
    532   // Find out which TabContents this renderer is attached to, and then
    533   // invalidate the associated snapshot so it'll update.
    534   BrowserListenerVector::iterator iter = listeners_.begin();
    535   while (iter != listeners_.end()) {
    536     for (int i = 0; i < (*iter)->count(); i++) {
    537       RenderWidgetHostView* view =
    538           (*iter)->GetTabContentsAt(i)->GetRenderWidgetHostView();
    539       if (view && view->GetRenderWidgetHost() == renderer) {
    540         (*iter)->MarkSnapshotAsDirty(i);
    541         return;
    542       }
    543     }
    544     ++iter;
    545   }
    546   DLOG(ERROR) << "SnapshotImageChanged, but we do not know which it is?";
    547 }
    548 
    549 void WmOverviewController::OnBrowserRemoved(const Browser* browser) {
    550   for (BrowserListenerVector::iterator i = listeners_.begin();
    551        i != listeners_.end(); ++i) {
    552     if ((*i)->browser() == browser) {
    553       listeners_.erase(i);
    554       return;
    555     }
    556   }
    557 }
    558 
    559 BrowserView* GetBrowserViewForGdkWindow(GdkWindow* gdk_window) {
    560   gpointer data = NULL;
    561   gdk_window_get_user_data(gdk_window, &data);
    562   GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
    563   if (widget) {
    564     GtkWindow* gtk_window = GTK_WINDOW(widget);
    565     return BrowserView::GetBrowserViewForNativeWindow(gtk_window);
    566   } else {
    567     return NULL;
    568   }
    569 }
    570 
    571 void WmOverviewController::ProcessWmMessage(const WmIpc::Message& message,
    572                                             GdkWindow* window) {
    573   switch (message.type()) {
    574     case WM_IPC_MESSAGE_CHROME_NOTIFY_LAYOUT_MODE: {
    575       layout_mode_ = message.param(0) == 0 ? ACTIVE_MODE : OVERVIEW_MODE;
    576       if (layout_mode_ == ACTIVE_MODE || BrowserList::size() == 0) {
    577         Hide(message.param(1) != 0);
    578       } else {
    579         Show();
    580       }
    581       break;
    582     }
    583     case WM_IPC_MESSAGE_CHROME_NOTIFY_TAB_SELECT: {
    584       BrowserView* browser_window = GetBrowserViewForGdkWindow(window);
    585       // Find out which listener this goes to, and send it there.
    586       for (BrowserListenerVector::iterator i = listeners_.begin();
    587            i != listeners_.end(); ++i) {
    588         if ((*i)->browser()->window() == browser_window) {
    589           // param(0): index of the tab to select.
    590           // param(1): timestamp of the event.
    591           (*i)->SelectTab(message.param(0), message.param(1));
    592           break;
    593         }
    594       }
    595       break;
    596     }
    597     default:
    598       break;
    599   }
    600 }
    601 
    602 void WmOverviewController::StartDelayTimer() {
    603   // We're rate limiting the number of times we can reconfigure the
    604   // snapshots.  If we were to restart the delay timer, it could
    605   // result in a very long delay until they get configured if tabs
    606   // keep changing.
    607   updating_snapshots_ = false;
    608   if (layout_mode_ == OVERVIEW_MODE) {
    609     delay_timer_.Start(
    610         base::TimeDelta::FromMilliseconds(kDelayTimeMs), this,
    611         &WmOverviewController::UpdateSnapshots);
    612   }
    613 }
    614 
    615 void WmOverviewController::RestoreTabSelections() {
    616   for (BrowserListenerVector::iterator i = listeners_.begin();
    617        i != listeners_.end(); ++i) {
    618     (*i)->RestoreOriginalSelectedTab();
    619   }
    620 }
    621 
    622 void WmOverviewController::SaveTabSelections() {
    623   for (BrowserListenerVector::iterator i = listeners_.begin();
    624        i != listeners_.end(); ++i) {
    625     (*i)->SaveCurrentTab();
    626   }
    627 }
    628 
    629 void WmOverviewController::Show() {
    630   SaveTabSelections();
    631 
    632   for (BrowserListenerVector::iterator i = listeners_.begin();
    633        i != listeners_.end(); ++i) {
    634     (*i)->ShowSnapshots();
    635   }
    636 
    637   // TODO(jiesun): Make the focused tab as the start point.
    638   browser_listener_index_ = 0;
    639   tab_contents_index_ = -1;
    640   UpdateSnapshots();
    641 }
    642 
    643 void WmOverviewController::Hide(bool cancelled) {
    644   delay_timer_.Stop();
    645   updating_snapshots_ = false;
    646   if (cancelled) {
    647     RestoreTabSelections();
    648   }
    649 }
    650 
    651 void WmOverviewController::UpdateSnapshots() {
    652 
    653   // Only updating snapshots during overview mode.
    654   if (layout_mode_ != OVERVIEW_MODE)
    655     return;
    656 
    657   // Only reloading snapshots when not already started.
    658   if (updating_snapshots_ || delay_timer_.IsRunning())
    659     return;
    660 
    661   // Only update one snapshot in round-robin mode.
    662   // Start delay timer after each update unless all snapshots had been updated.
    663   if (!listeners_.size())
    664     return;
    665 
    666   if (int(listeners_.size()) <= browser_listener_index_) {
    667     DLOG(INFO) << "Browser listener(s) have disappeared since last update";
    668     browser_listener_index_ = 0;
    669     tab_contents_index_ = -1;
    670   } else {
    671     BrowserListener* listener = listeners_[browser_listener_index_].get();
    672     if (listener->count() <= tab_contents_index_) {
    673       DLOG(INFO) << "Tab content(s) have disappeared since last update";
    674       tab_contents_index_ = -1;
    675     }
    676   }
    677 
    678   int browser_listener_index = browser_listener_index_;
    679   int tab_contents_index = tab_contents_index_;
    680 
    681   bool loop_back = false;
    682   while (1) {
    683     BrowserListener* listener = listeners_[browser_listener_index].get();
    684     tab_contents_index =
    685         listener->ConfigureNextUnconfiguredSnapshot(tab_contents_index);
    686     if (tab_contents_index >= 0) {
    687       updating_snapshots_ = true;  // Prevent future parallel updates.
    688       browser_listener_index_ = browser_listener_index;
    689       tab_contents_index_ = tab_contents_index;
    690       return;
    691     }
    692 
    693     // Found next one;
    694     browser_listener_index++;
    695     browser_listener_index = browser_listener_index % listeners_.size();
    696     tab_contents_index = -1;
    697 
    698     if (loop_back)
    699       break;
    700     loop_back = browser_listener_index == browser_listener_index_;
    701   }
    702 
    703   // All snapshots have been fully updated.
    704   updating_snapshots_ = false;
    705 }
    706 
    707 void WmOverviewController::AddAllBrowsers() {
    708   // Make a copy so the old ones aren't deleted yet.
    709   BrowserListenerVector old_listeners;
    710 
    711   listeners_.swap(old_listeners);
    712 
    713   // Iterator through the browser list, adding all the browsers in the
    714   // new order.  If they were in the old list of listeners, just copy
    715   // that linked pointer, instead of making a new listener, so that we
    716   // can avoid lots of spurious destroy/create messages.
    717   BrowserList::const_iterator iterator = BrowserList::begin();
    718   while (iterator != BrowserList::end()) {
    719     // Don't add a browser to the list if that type of browser doesn't
    720     // have snapshots in overview mode.
    721     if ((*iterator)->type() != Browser::TYPE_NORMAL &&
    722         (*iterator)->type() != Browser::TYPE_APP) {
    723       ++iterator;
    724       continue;
    725     }
    726 
    727     BrowserListenerVector::value_type item(
    728         BrowserListenerVector::value_type(NULL));
    729     for (BrowserListenerVector::iterator old_iter = old_listeners.begin();
    730          old_iter != old_listeners.end(); ++old_iter) {
    731       if ((*old_iter)->browser() == *iterator) {
    732         item = *old_iter;
    733         break;
    734       }
    735     }
    736 
    737     // This browser isn't tracked by any listener, so create it.
    738     if (item.get() == NULL) {
    739       item = BrowserListenerVector::value_type(
    740           new BrowserListener(*iterator, this));
    741     }
    742     listeners_.push_back(item);
    743     ++iterator;
    744   }
    745 }
    746 
    747 }  // namespace chromeos
    748