Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(404)

Unified Diff: chrome/browser/chromeos/wm_overview_controller.cc

Issue 661237: This adds in the ability for Chrome to generate windows with snapshots of all... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/chromeos/wm_overview_controller.h ('k') | chrome/browser/chromeos/wm_overview_snapshot.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chromeos/wm_overview_controller.cc
===================================================================
--- chrome/browser/chromeos/wm_overview_controller.cc (revision 0)
+++ chrome/browser/chromeos/wm_overview_controller.cc (revision 0)
@@ -0,0 +1,517 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/wm_overview_controller.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/linked_ptr.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/wm_ipc.h"
+#include "chrome/browser/chromeos/wm_overview_snapshot.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/tab_contents/thumbnail_generator.h"
+#include "chrome/browser/views/frame/browser_extender.h"
+#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/common/notification_service.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_gtk.h"
+#include "views/window/window.h"
+
+using std::vector;
+
+#if !defined(OS_CHROMEOS)
+#error This file is only meant to be compiled for ChromeOS
+#endif
+
+namespace chromeos {
+
+class BrowserListener : public TabStripModelObserver {
+ public:
+ BrowserListener(Browser* browser, WmOverviewController* parent);
+ ~BrowserListener();
+
+ // Begin TabStripModelObserver methods
+ virtual void TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground);
+ virtual void TabClosingAt(TabContents* contents, int index) {}
+ virtual void TabDetachedAt(TabContents* contents, int index);
+ virtual void TabMoved(TabContents* contents,
+ int from_index,
+ int to_index);
+ virtual void TabChangedAt(TabContents* contents, int index,
+ TabStripModelObserver::TabChangeType change_type);
+ virtual void TabStripEmpty();
+ virtual void TabDeselectedAt(TabContents* contents, int index) {}
+ virtual void TabSelectedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ bool user_gesture);
+ // End TabStripModelObserver methods
+
+ // Returns the number of tabs in this child.
+ int count() const { return browser_->tabstrip_model()->count(); }
+
+ // Returns the browser that this child gets its data from.
+ Browser* browser() const { return browser_; }
+
+ // Removes all the snapshots and re-populates them from the browser.
+ void RecreateSnapshots();
+
+ // Updates the selected index and tab count on the toplevel window.
+ void UpdateSelectedIndex(int index);
+
+ // Finds the first cell with no snapshot and invokes ConfigureCell
+ // for it. Returns false if there are no more cells to configure on
+ // this listener.
+ bool ConfigureNextUnconfiguredSnapshot();
+
+ // Saves the currently selected tab.
+ void SaveCurrentTab() { original_selected_tab_ = browser_->selected_index(); }
+
+ // Reverts the selected browser tab to the tab that was selected
+ // when This BrowserListener was created, or the last time
+ // SaveCurrentTab was called.
+ void RestoreOriginalSelectedTab();
+
+ // Selects the tab at the given index.
+ void SelectTab(int index);
+
+ // Shows any snapshots that are not visible, and updates their
+ // bitmaps.
+ void ShowSnapshots();
+
+ private:
+ // Returns the tab contents from the tab model for this child at index.
+ TabContents* GetTabContentsAt(int index) const {
+ return browser_->tabstrip_model()->GetTabContentsAt(index);
+ }
+
+ // Configures a cell from the tab contents.
+ void ConfigureCell(WmOverviewSnapshot* cell, TabContents* contents);
+
+ // Configures a cell from the model.
+ void ConfigureCell(WmOverviewSnapshot* cell, int index) {
+ ConfigureCell(cell, GetTabContentsAt(index));
+ }
+
+ // Inserts a new snapshot, initialized from the model, at the given
+ // index, and renumbers any following snapshots.
+ void InsertSnapshot(int index);
+
+ // Removes the snapshot at index.
+ void ClearSnapshot(int index);
+
+ // Renumbers the index atom in the snapshots starting at the given
+ // index.
+ void RenumberSnapshots(int start_index);
+
+ Browser* browser_; // Not owned
+ WmOverviewController* controller_; // Not owned
+
+ // Widgets containing snapshot images for this browser.
+ typedef std::vector<WmOverviewSnapshot* > SnapshotVector;
+ SnapshotVector snapshots_;
+
+ // True if the snapshots are showing.
+ bool snapshots_showing_;
+
+ // The tab selected the last time SaveCurrentTab is called.
+ int original_selected_tab_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserListener);
+};
+
+BrowserListener::BrowserListener(Browser* browser,
+ WmOverviewController* controller)
+ : browser_(browser),
+ controller_(controller),
+ snapshots_showing_(false),
+ original_selected_tab_(-1) {
+ CHECK(browser_);
+ CHECK(controller_);
+ browser_->tabstrip_model()->AddObserver(this);
+}
+
+BrowserListener::~BrowserListener() {
+ browser_->tabstrip_model()->RemoveObserver(this);
+}
+
+void BrowserListener::TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground) {
+ InsertSnapshot(index);
+ RenumberSnapshots(index);
+ UpdateSelectedIndex(browser_->selected_index());
+}
+
+void BrowserListener::TabDetachedAt(TabContents* contents, int index) {
+ ClearSnapshot(index);
+ UpdateSelectedIndex(browser_->selected_index());
+ RenumberSnapshots(index);
+}
+
+void BrowserListener::TabMoved(TabContents* contents,
+ int from_index,
+ int to_index) {
+ // Need to reorder tab in the snapshots list, and reset the window
+ // type atom on the affected snapshots (the one moved, and all the
+ // ones after it), so that their indices are correct.
+ WmOverviewSnapshot* snapshot = snapshots_[from_index];
+ snapshots_.erase(snapshots_.begin() + from_index);
+ snapshots_.insert(snapshots_.begin() + to_index, snapshot);
+
+ RenumberSnapshots(std::min(to_index, from_index));
+}
+
+void BrowserListener::TabChangedAt(
+ TabContents* contents,
+ int index,
+ TabStripModelObserver::TabChangeType change_type) {
+ snapshots_[index]->reload_snapshot();
+ controller_->StartDelayTimer();
+}
+
+void BrowserListener::TabStripEmpty() {
+ snapshots_.clear();
+}
+
+void BrowserListener::TabSelectedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ bool user_gesture) {
+ UpdateSelectedIndex(index);
+}
+
+void BrowserListener::RecreateSnapshots() {
+ snapshots_.clear();
+
+ for (int i = 0; i < count(); ++i) {
+ InsertSnapshot(i);
+ }
+
+ RenumberSnapshots(0);
+}
+
+void BrowserListener::UpdateSelectedIndex(int index) {
+ // Get the window params and check to make sure that they are
+ // different from what we know before we set them, to avoid extra
+ // notifications.
+ std::vector<int> params;
+ WmIpc::WindowType type = WmIpc::instance()->GetWindowType(
+ GTK_WIDGET(browser_->window()->GetNativeHandle()),
+ &params);
+ DCHECK(type == WmIpc::WINDOW_TYPE_CHROME_TOPLEVEL);
+ if (params.size() > 1) {
+ if (params[0] == browser_->tab_count() &&
+ params[0] == index)
+ return;
+ }
+
+ params.clear();
+ params.push_back(browser_->tab_count());
+ params.push_back(index);
+ WmIpc::instance()->SetWindowType(
+ GTK_WIDGET(browser_->window()->GetNativeHandle()),
+ WmIpc::WINDOW_TYPE_CHROME_TOPLEVEL,
+ &params);
+}
+
+bool BrowserListener::ConfigureNextUnconfiguredSnapshot() {
+ for (SnapshotVector::size_type i = 0; i < snapshots_.size(); ++i) {
+ WmOverviewSnapshot* cell = snapshots_[i];
+ if (!cell->configured_snapshot()) {
+ ConfigureCell(cell, GetTabContentsAt(i));
+ return true;
+ }
+ }
+ return false;
+}
+
+void BrowserListener::RestoreOriginalSelectedTab() {
+ if (original_selected_tab_ >= 0) {
+ browser_->SelectTabContentsAt(original_selected_tab_, false);
+ }
+}
+
+void BrowserListener::ShowSnapshots() {
+ for (SnapshotVector::size_type i = 0; i < snapshots_.size(); ++i) {
+ WmOverviewSnapshot* snapshot = snapshots_[i];
+ snapshot->reload_snapshot();
+ if (!snapshot->IsVisible()) {
+ snapshot->Show();
+ }
+ }
+}
+
+void BrowserListener::SelectTab(int index) {
+ browser_->SelectTabContentsAt(index, true);
+}
+
+void BrowserListener::ConfigureCell(WmOverviewSnapshot* cell,
+ TabContents* contents) {
+ if (contents) {
+ if (controller_->allow_show_snapshots()) {
+ ThumbnailGenerator* generator =
+ g_browser_process->GetThumbnailGenerator();
+ // TODO: Make sure that if the cell gets deleted before the
+ // callback is called that it sticks around until it gets
+ // called. (some kind of "in flight" list that uses linked_ptr
+ // to make sure they don't actually get deleted?) Also, make
+ // sure that any request for a thumbnail eventually returns
+ // (even if it has bogus data), so we don't leak orphaned cells.
+ ThumbnailGenerator::ThumbnailReadyCallback* callback =
+ NewCallback(cell, &WmOverviewSnapshot::SetImage);
+ generator->AskForThumbnail(contents->render_view_host(),
+ callback, cell->size());
+ }
+ } else {
+ // This happens because the contents haven't been loaded yet.
+
+ // Make sure we set the snapshot image to something, otherwise
+ // configured_snapshot remains false and ConfigureNextUnconfiguredSnapshot
+ // would get stuck.
+ if (controller_->allow_show_snapshots()) {
+ cell->SetImage(SkBitmap());
+ }
+ }
+}
+
+void BrowserListener::InsertSnapshot(int index) {
+ WmOverviewSnapshot* snapshot = new WmOverviewSnapshot;
+ gfx::Rect bounds =
+ static_cast<BrowserView*>(browser_->window())->GetClientAreaBounds();
+ gfx::Size size(bounds.width()/2, bounds.height()/2);
+ snapshot->Init(size, browser_, index);
+ snapshots_.insert(snapshots_.begin() + index, snapshot);
+ snapshot->reload_snapshot();
+ controller_->StartDelayTimer();
+}
+
+// Removes the snapshot at index.
+void BrowserListener::ClearSnapshot(int index) {
+ snapshots_[index]->CloseNow();
+ snapshots_.erase(snapshots_.begin() + index);
+}
+
+void BrowserListener::RenumberSnapshots(int start_index) {
+ int changes = 0;
+ for (SnapshotVector::size_type i = start_index; i < snapshots_.size(); ++i) {
+ if (snapshots_[i]->index() != static_cast<int>(i)) {
+ snapshots_[i]->UpdateIndex(browser_, i);
+ changes++;
+ }
+ }
+}
+
+///////////////////////////////////
+// WmOverviewController methods
+
+// static
+WmOverviewController* WmOverviewController::instance() {
+ static WmOverviewController* instance = NULL;
+ if (!instance) {
+ instance = Singleton<WmOverviewController>::get();
+ }
+ return instance;
+}
+
+WmOverviewController::WmOverviewController()
+ : allow_show_snapshots_(false) {
+ AddAllBrowsers();
+ BrowserList::AddObserver(this);
+ WmMessageListener::instance()->AddObserver(this);
+}
+
+WmOverviewController::~WmOverviewController() {
+ WmMessageListener::instance()->RemoveObserver(this);
+ BrowserList::RemoveObserver(this);
+ listeners_.clear();
+}
+
+void WmOverviewController::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // Now that the browser window is ready, we create the snapshots.
+ if (type == NotificationType::BROWSER_WINDOW_READY) {
+ const Browser* browser = Source<const Browser>(source).ptr();
+ BrowserListenerVector::value_type new_listener(
+ new BrowserListener(const_cast<Browser*>(browser), this));
+ listeners_.push_back(new_listener);
+ new_listener->RecreateSnapshots();
+
+ // This makes sure that the new listener is in the right order (to
+ // match the order in the browser list).
+ AddAllBrowsers();
+ }
+}
+
+// Called immediately before a browser is removed from the list.
+void WmOverviewController::OnBrowserRemoving(const Browser* browser) {
+ for (BrowserListenerVector::iterator i = listeners_.begin();
+ i != listeners_.end(); ++i) {
+ if ((*i)->browser() == browser) {
+ listeners_.erase(i);
+ return;
+ }
+ }
+}
+
+BrowserView* GetBrowserViewForGdkWindow(GdkWindow* gdk_window) {
+ gpointer data = NULL;
+ gdk_window_get_user_data(gdk_window, &data);
+ GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
+ if (widget) {
+ GtkWindow* gtk_window = GTK_WINDOW(widget);
+ return BrowserView::GetBrowserViewForNativeWindow(gtk_window);
+ } else {
+ return NULL;
+ }
+}
+
+void WmOverviewController::ProcessWmMessage(const WmIpc::Message& message,
+ GdkWindow* window) {
+ switch (message.type()) {
+ case WmIpc::Message::CHROME_NOTIFY_LAYOUT_MODE: {
+ if (message.param(0) == 0 || BrowserList::size() == 0) {
+ Hide(message.param(1) != 0);
+ } else {
+ Show();
+ }
+ break;
+ }
+ case WmIpc::Message::CHROME_NOTIFY_TAB_SELECT: {
+ BrowserView* browser_window = GetBrowserViewForGdkWindow(window);
+ // Find out which listener this goes to, and send it there.
+ for (BrowserListenerVector::iterator i = listeners_.begin();
+ i != listeners_.end(); ++i) {
+ if ((*i)->browser()->window() == browser_window) {
+ (*i)->SelectTab(message.param(0));
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void WmOverviewController::StartDelayTimer() {
+ // We leave the delay timer running if it already is -- this means
+ // we're rate limiting the number of times we can reconfigure the
+ // snapshots (at most once every 350ms). If we were to restart the
+ // delay timer, it could result in a very long delay until they get
+ // configured if tabs keep changing.
+ if (!delay_timer_.IsRunning()) {
+ configure_timer_.Stop();
+ // Note that this pause is kind of a hack: it's just long enough
+ // that the overview-mode transitions will have finished happening
+ // before we start refreshing snapshots, so we don't bog the CPU
+ // while it's trying to animate the overview transitions.
+ delay_timer_.Start(
+ base::TimeDelta::FromMilliseconds(350), this,
+ &WmOverviewController::StartConfiguring);
+ }
+}
+
+void WmOverviewController::RestoreTabSelections() {
+ for (BrowserListenerVector::iterator i = listeners_.begin();
+ i != listeners_.end(); ++i) {
+ (*i)->RestoreOriginalSelectedTab();
+ }
+}
+
+void WmOverviewController::SaveTabSelections() {
+ for (BrowserListenerVector::iterator i = listeners_.begin();
+ i != listeners_.end(); ++i) {
+ (*i)->SaveCurrentTab();
+ }
+}
+
+void WmOverviewController::Show() {
+ SaveTabSelections();
+ for (BrowserListenerVector::iterator i = listeners_.begin();
+ i != listeners_.end(); ++i) {
+ (*i)->ShowSnapshots();
+ }
+ allow_show_snapshots_ = false;
+ StartDelayTimer();
+}
+
+void WmOverviewController::Hide(bool cancelled) {
+ configure_timer_.Stop();
+ delay_timer_.Stop();
+ if (cancelled) {
+ RestoreTabSelections();
+ }
+}
+
+void WmOverviewController::StartConfiguring() {
+ allow_show_snapshots_ = true;
+ configure_timer_.Stop();
+ configure_timer_.Start(
+ base::TimeDelta::FromMilliseconds(10), this,
+ &WmOverviewController::ConfigureNextUnconfiguredSnapshot);
+}
+
+// Just configure one unconfigured cell. If there aren't any left,
+// then stop the timer.
+void WmOverviewController::ConfigureNextUnconfiguredSnapshot() {
+ for (BrowserListenerVector::size_type i = 0; i < listeners_.size(); ++i) {
+ BrowserListener* listener = listeners_[i].get();
+ if (listener->ConfigureNextUnconfiguredSnapshot())
+ return;
+ }
+ configure_timer_.Stop();
+}
+
+void WmOverviewController::AddAllBrowsers() {
+ // Make a copy so the old ones aren't deleted yet.
+ BrowserListenerVector old_listeners;
+
+ listeners_.swap(old_listeners);
+
+ // Iterator through the browser list, adding all the browsers in the
+ // new order. If they were in the old list of listeners, just copy
+ // that linked pointer, instead of making a new listener, so that we
+ // can avoid lots of spurious destroy/create messages.
+ BrowserList::const_iterator iterator = BrowserList::begin();
+ while (iterator != BrowserList::end()) {
+ BrowserListenerVector::value_type item(
+ BrowserListenerVector::value_type(NULL));
+ for (BrowserListenerVector::iterator old_iter = old_listeners.begin();
+ old_iter != old_listeners.end(); ++old_iter) {
+ if ((*old_iter)->browser() == *iterator) {
+ item = *old_iter;
+ break;
+ }
+ }
+
+ // This browser isn't owned by any listener, so create it.
+ if (item.get() == NULL) {
+ item = BrowserListenerVector::value_type(
+ new BrowserListener(*iterator, this));
+
+ // This browser didn't already exist, and so we haven't been
+ // watching it for tab insertions, so we need to create the
+ // snapshots associated with it.
+ item->RecreateSnapshots();
+ }
+ listeners_.push_back(item);
+ ++iterator;
+ }
+
+ // Make sure we get notifications for when browser windows are ready.
+ if (registrar_.IsEmpty())
+ registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY,
+ NotificationService::AllSources());
+}
+
+} // namespace chromeos
Property changes on: chrome/browser/chromeos/wm_overview_controller.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/browser/chromeos/wm_overview_controller.h ('k') | chrome/browser/chromeos/wm_overview_snapshot.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698