• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
TabClosingAt(TabStripModel * tab_strip_model,TabContentsWrapper * contents,int index)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();
TabDeselected(TabContentsWrapper * contents)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.
count() const88   int count() const { return browser_->tabstrip_model()->count(); }
89 
90   // Returns the browser that this child gets its data from.
browser() const91   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.
SaveCurrentTab()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.
GetTabContentsAt(int index) const128   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.
ConfigureCell(WmOverviewSnapshot * cell,int index)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 
BrowserListener(Browser * browser,WmOverviewController * controller)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 
~BrowserListener()202 BrowserListener::~BrowserListener() {
203   browser_->tabstrip_model()->RemoveObserver(this);
204 }
205 
TabInsertedAt(TabContentsWrapper * contents,int index,bool foreground)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 
TabDetachedAt(TabContentsWrapper * contents,int index)214 void BrowserListener::TabDetachedAt(TabContentsWrapper* contents, int index) {
215   ClearSnapshot(index);
216   UpdateSelectedIndex(browser_->active_index());
217   RenumberSnapshots(index);
218 }
219 
TabMoved(TabContentsWrapper * contents,int from_index,int to_index)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 
TabChangedAt(TabContentsWrapper * contents,int index,TabStripModelObserver::TabChangeType change_type)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 
TabStripEmpty()248 void BrowserListener::TabStripEmpty() {
249   snapshots_.clear();
250 }
251 
TabSelectedAt(TabContentsWrapper * old_contents,TabContentsWrapper * new_contents,int index,bool user_gesture)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 
MarkSnapshotAsDirty(int index)262 void BrowserListener::MarkSnapshotAsDirty(int index) {
263   snapshots_[index].snapshot->reload_snapshot();
264   controller_->UpdateSnapshots();
265 }
266 
RecreateSnapshots()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 
UpdateSelectedIndex(int index)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 
ConfigureNextUnconfiguredSnapshot(int start_from)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 
RestoreOriginalSelectedTab()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 
ShowSnapshots()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 
SelectTab(int index,uint32 timestamp)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 
CalculateCellSize()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 
OnSnapshotReady(const SkBitmap & sk_bitmap)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 
ConfigureCell(WmOverviewSnapshot * cell,TabContents * contents)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 
InsertSnapshot(int index)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.
ClearSnapshot(int 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 
RenumberSnapshots(int start_index)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
GetInstance()460 WmOverviewController* WmOverviewController::GetInstance() {
461   static WmOverviewController* instance = NULL;
462   if (!instance) {
463     instance = Singleton<WmOverviewController>::get();
464   }
465   return instance;
466 }
467 
WmOverviewController()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 
~WmOverviewController()493 WmOverviewController::~WmOverviewController() {
494   WmMessageListener::GetInstance()->RemoveObserver(this);
495   BrowserList::RemoveObserver(this);
496   listeners_.clear();
497 }
498 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
SnapshotImageChanged(RenderWidgetHost * renderer)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 
OnBrowserRemoved(const Browser * browser)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 
GetBrowserViewForGdkWindow(GdkWindow * gdk_window)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 
ProcessWmMessage(const WmIpc::Message & message,GdkWindow * window)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 
StartDelayTimer()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 
RestoreTabSelections()615 void WmOverviewController::RestoreTabSelections() {
616   for (BrowserListenerVector::iterator i = listeners_.begin();
617        i != listeners_.end(); ++i) {
618     (*i)->RestoreOriginalSelectedTab();
619   }
620 }
621 
SaveTabSelections()622 void WmOverviewController::SaveTabSelections() {
623   for (BrowserListenerVector::iterator i = listeners_.begin();
624        i != listeners_.end(); ++i) {
625     (*i)->SaveCurrentTab();
626   }
627 }
628 
Show()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 
Hide(bool cancelled)643 void WmOverviewController::Hide(bool cancelled) {
644   delay_timer_.Stop();
645   updating_snapshots_ = false;
646   if (cancelled) {
647     RestoreTabSelections();
648   }
649 }
650 
UpdateSnapshots()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 
AddAllBrowsers()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