diff options
author | zelidrag@google.com <zelidrag@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-15 21:49:44 +0000 |
---|---|---|
committer | zelidrag@google.com <zelidrag@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-15 21:49:44 +0000 |
commit | fa1cf0b87092ed3f3069a8549270f999e05cca20 (patch) | |
tree | 71c08950f340004c1107776d0d4962d8b38bfb8e /chrome/browser | |
parent | 18db63ea67ad2f5e428022e32ff55de83c0db0ca (diff) | |
download | chromium_src-fa1cf0b87092ed3f3069a8549270f999e05cca20.zip chromium_src-fa1cf0b87092ed3f3069a8549270f999e05cca20.tar.gz chromium_src-fa1cf0b87092ed3f3069a8549270f999e05cca20.tar.bz2 |
Tab-modal dialog improvements:
- treat constrained dialogs as tab-modal - only one shows at the time
- added visual indication (tab pulsing) to the tab strip when a tab is blocked by a tab-modal dialog
- blocked all UI activity from rendrer host and forced refocusing on constrained (tab-modal) dialogs
This CL reverts http://codereview.chromium.org/384113 and instead incorporates the changes from http://codereview.chromium.org/392018.
BUG=456,27585,27620
TEST=Go to http://www/~thakis/cgi-bin/test.html, hit esc.
Review URL: http://codereview.chromium.org/541056
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36415 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
37 files changed, 290 insertions, 124 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 0f00ab4..bcf74d1 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -2165,6 +2165,15 @@ void Browser::ContentsZoomChange(bool zoom_in) { ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS); } +void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) { + int index = tabstrip_model()->GetIndexOfTabContents(contents); + if (index == TabStripModel::kNoTab) { + NOTREACHED(); + return; + } + tabstrip_model()->SetTabBlocked(index, blocked); +} + void Browser::TabContentsFocused(TabContents* tab_content) { window_->TabContentsFocused(tab_content); } diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index a354a62..50fd49d 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -571,6 +571,7 @@ class Browser : public TabStripModelDelegate, virtual void ContentsMouseEvent( TabContents* source, const gfx::Point& location, bool motion); virtual void ContentsZoomChange(bool zoom_in); + virtual void SetTabContentBlocked(TabContents* contents, bool blocked); virtual void TabContentsFocused(TabContents* tab_content); virtual bool TakeFocus(bool reverse); virtual bool IsApplication() const; diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h index ed2b18b..9a15e39 100644 --- a/chrome/browser/cocoa/browser_window_controller.h +++ b/chrome/browser/cocoa/browser_window_controller.h @@ -209,12 +209,7 @@ class TabStripModelObserverBridge; - (GTMWindowSheetController*)sheetController; // Requests that |window| is opened as a per-tab sheet to the current tab. -// Returns YES if the window became the active per-tab sheet of the current tab, -// or NO if the current tab already has a per-tab sheet. If this returns NO, -// the window's |Realize()| method will be called again when the curren sheet -// disappears. The window should then call |attachConstrainedWindow:| again. -- (BOOL)attachConstrainedWindow:(ConstrainedWindowMac*)window; - +- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window; // Closes the tab sheet |window| and potentially shows the next sheet in the // tab's sheet queue. - (void)removeConstrainedWindow:(ConstrainedWindowMac*)window; diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index d8be276..51d1ced 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -385,8 +385,8 @@ willPositionSheet:(NSWindow*)sheet afterDelay:0]; } -- (BOOL)attachConstrainedWindow:(ConstrainedWindowMac*)window { - return [tabStripController_ attachConstrainedWindow:window]; +- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window { + [tabStripController_ attachConstrainedWindow:window]; } - (void)removeConstrainedWindow:(ConstrainedWindowMac*)window { diff --git a/chrome/browser/cocoa/constrained_window_mac.h b/chrome/browser/cocoa/constrained_window_mac.h index 83331c7..0fd315d 100644 --- a/chrome/browser/cocoa/constrained_window_mac.h +++ b/chrome/browser/cocoa/constrained_window_mac.h @@ -117,6 +117,7 @@ class ConstrainedWindowMac : public ConstrainedWindow { virtual ~ConstrainedWindowMac(); // Overridden from ConstrainedWindow: + virtual void ShowConstrainedWindow(); virtual void CloseConstrainedWindow(); // Returns the TabContents that constrains this Constrained Window. @@ -125,12 +126,9 @@ class ConstrainedWindowMac : public ConstrainedWindow { // Returns the window's delegate. ConstrainedWindowMacDelegate* delegate() { return delegate_; } - // Tells |controller_| that the sheet would like to be displayed. + // Makes the constrained window visible, if it is not yet visible. void Realize(BrowserWindowController* controller); - // Called by |controller_| to inform the sheet that it now is visible. - void SetVisible(); - private: friend class ConstrainedWindow; @@ -146,6 +144,9 @@ class ConstrainedWindowMac : public ConstrainedWindow { // Controller of the window that contains this sheet. BrowserWindowController* controller_; + // Stores if |ShowConstrainedWindow()| was called. + bool should_be_visible_; + DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowMac); }; diff --git a/chrome/browser/cocoa/constrained_window_mac.mm b/chrome/browser/cocoa/constrained_window_mac.mm index ad090a8..eec4dba 100644 --- a/chrome/browser/cocoa/constrained_window_mac.mm +++ b/chrome/browser/cocoa/constrained_window_mac.mm @@ -46,10 +46,16 @@ ConstrainedWindowMac::ConstrainedWindowMac( TabContents* owner, ConstrainedWindowMacDelegate* delegate) : owner_(owner), delegate_(delegate), - controller_(nil) { + controller_(nil), + should_be_visible_(false) { DCHECK(owner); DCHECK(delegate); +} + +ConstrainedWindowMac::~ConstrainedWindowMac() {} +void ConstrainedWindowMac::ShowConstrainedWindow() { + should_be_visible_ = true; // The TabContents only has a native window if it is currently visible. In // this case, open the sheet now. Else, Realize() will be called later, when // our tab becomes visible. @@ -61,8 +67,6 @@ ConstrainedWindowMac::ConstrainedWindowMac( } } -ConstrainedWindowMac::~ConstrainedWindowMac() {} - void ConstrainedWindowMac::CloseConstrainedWindow() { // Note: controller_ can be `nil` here if the sheet was never realized. That's // ok. @@ -74,6 +78,9 @@ void ConstrainedWindowMac::CloseConstrainedWindow() { } void ConstrainedWindowMac::Realize(BrowserWindowController* controller) { + if (!should_be_visible_) + return; + if (controller_ != nil) { DCHECK(controller_ == controller); return; @@ -82,13 +89,7 @@ void ConstrainedWindowMac::Realize(BrowserWindowController* controller) { // Remember the controller we're adding ourselves to, so that we can later // remove us from it. - if ([controller attachConstrainedWindow:this]) - controller_ = controller; -} - -void ConstrainedWindowMac::SetVisible() { - // Only notify the delegate that the sheet is open after the sheet appeared - // on screen (as opposed to when the sheet was added to the current tab's - // sheet queue). + controller_ = controller; + [controller_ attachConstrainedWindow:this]; delegate_->set_sheet_open(true); } diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h index f5f8d9d..8bc3b00 100644 --- a/chrome/browser/cocoa/tab_strip_controller.h +++ b/chrome/browser/cocoa/tab_strip_controller.h @@ -7,9 +7,6 @@ #import <Cocoa/Cocoa.h> -#include <deque> -#include <map> - #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" #import "chrome/browser/cocoa/tab_controller_target.h" @@ -53,7 +50,7 @@ class ToolbarModel; scoped_ptr<TabStripModelObserverBridge> bridge_; Browser* browser_; // weak TabStripModel* tabStripModel_; // weak - + // Access to the TabContentsControllers (which own the parent view // for the toolbar and associated tab contents) given an index. Call // |indexFromModelIndex:| to convert a |tabStripModel_| index to a @@ -110,12 +107,6 @@ class ToolbarModel; // Is the mouse currently inside the strip; BOOL mouseInside_; - - // GTMWindowSheetController supports only one per-tab sheet at a time. - // Thus, keep a queue of sheets for every tab. The first element in the queue - // is the currently visible sheet, and when this sheet is closed, the next - // sheet in the queue will be shown. - std::map<NSView*, std::deque<ConstrainedWindowMac*> > constrainedWindows_; } // Initialize the controller with a view and browser that contains @@ -192,9 +183,9 @@ class ToolbarModel; // Returns the currently active TabContentsController. - (TabContentsController*)activeTabContentsController; -// See comments in browser_window_controller.h for documentation about these -// functions. -- (BOOL)attachConstrainedWindow:(ConstrainedWindowMac*)window; + // See comments in browser_window_controller.h for documentation about these + // functions. +- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window; - (void)removeConstrainedWindow:(ConstrainedWindowMac*)window; - (void)updateDevToolsForContents:(TabContents*)contents; diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm index 14eb3c7..8c2eac0 100644 --- a/chrome/browser/cocoa/tab_strip_controller.mm +++ b/chrome/browser/cocoa/tab_strip_controller.mm @@ -417,13 +417,11 @@ private: DCHECK(newTab); if (newTab) { TabContents::ConstrainedWindowList::iterator it, end; - it = newTab->constrained_window_begin(); end = newTab->constrained_window_end(); + NSWindowController* controller = [[newView window] windowController]; + DCHECK([controller isKindOfClass:[BrowserWindowController class]]); - // GTMWindowSheetController supports only one sheet at a time. - if (it != end) { - NSWindowController* controller = [[newView window] windowController]; - DCHECK([controller isKindOfClass:[BrowserWindowController class]]); + for (it = newTab->constrained_window_begin(); it != end; ++it) { ConstrainedWindow* constrainedWindow = *it; static_cast<ConstrainedWindowMac*>(constrainedWindow)->Realize( static_cast<BrowserWindowController*>(controller)); @@ -1637,7 +1635,7 @@ private: if (modelIndex < 0) return nil; NSInteger index = [self indexFromModelIndex:modelIndex]; - if (index < 0 || + if (index < 0 || index >= (NSInteger)[tabContentsArray_ count]) return nil; return [tabContentsArray_ objectAtIndex:index]; @@ -1656,7 +1654,7 @@ private: tabStripModel_->SelectTabContentsAt(index, false /* not a user gesture */); } -- (BOOL)attachConstrainedWindow:(ConstrainedWindowMac*)window { +- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window { // TODO(thakis, avi): Figure out how to make this work when tabs are dragged // out or if fullscreen mode is toggled. @@ -1669,6 +1667,7 @@ private: // to pass it to the sheet controller here. NSView* tabContentsView = [[window->owner()->GetNativeView() superview] superview]; + window->delegate()->RunSheet([self sheetController], tabContentsView); // TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets // between windows. Until then, we have to prevent having to move a tabsheet @@ -1680,23 +1679,8 @@ private: DCHECK(controller != nil); DCHECK(index >= 0); if (index >= 0) { - NSView* tab = [self viewAtIndex:index]; - [controller setTab:tab isDraggable:NO]; - - std::deque<ConstrainedWindowMac*>& windows = constrainedWindows_[tab]; - std::deque<ConstrainedWindowMac*>::iterator it = - find(windows.begin(), windows.end(), window); - if (it == windows.end()) - constrainedWindows_[tab].push_back(window); - - if (constrainedWindows_[tab].size() == 1) { - [controller setTab:tab isDraggable:NO]; - window->SetVisible(); - window->delegate()->RunSheet([self sheetController], tabContentsView); - return YES; - } + [controller setTab:[self viewAtIndex:index] isDraggable:NO]; } - return NO; } - (void)removeConstrainedWindow:(ConstrainedWindowMac*)window { @@ -1712,28 +1696,7 @@ private: (BrowserWindowController*)[[switchView_ window] windowController]; DCHECK(index >= 0); if (index >= 0) { - NSView* tab = [self viewAtIndex:index]; - - std::deque<ConstrainedWindowMac*>& windows = constrainedWindows_[tab]; - std::deque<ConstrainedWindowMac*>::iterator it = - find(windows.begin(), windows.end(), window); - DCHECK(it != windows.end()); - - bool removedVisibleSheet = it == windows.begin(); - - if (it != windows.end()) - windows.erase(it); - - if (windows.size() == 0) { - [controller setTab:tab isDraggable:YES]; - constrainedWindows_.erase(tab); - } else if (removedVisibleSheet && tab == [self selectedTabView]) { - // Show next sheet - NSWindowController* controller = [[tab window] windowController]; - DCHECK([controller isKindOfClass:[BrowserWindowController class]]); - windows.front()->Realize( - static_cast<BrowserWindowController*>(controller)); - } + [controller setTab:[self viewAtIndex:index] isDraggable:YES]; } } diff --git a/chrome/browser/gtk/constrained_window_gtk.cc b/chrome/browser/gtk/constrained_window_gtk.cc index 1f53a59..c6380d6 100644 --- a/chrome/browser/gtk/constrained_window_gtk.cc +++ b/chrome/browser/gtk/constrained_window_gtk.cc @@ -11,7 +11,8 @@ ConstrainedWindowGtk::ConstrainedWindowGtk( TabContents* owner, ConstrainedWindowGtkDelegate* delegate) : owner_(owner), - delegate_(delegate) { + delegate_(delegate), + visible_(false) { DCHECK(owner); DCHECK(delegate); GtkWidget* dialog = delegate->GetWidgetRoot(); @@ -29,20 +30,25 @@ ConstrainedWindowGtk::ConstrainedWindowGtk( gtk_container_add(GTK_CONTAINER(frame), alignment); gtk_container_add(GTK_CONTAINER(ebox), frame); border_.Own(ebox); +} + +ConstrainedWindowGtk::~ConstrainedWindowGtk() { + border_.Destroy(); +} +void ConstrainedWindowGtk::ShowConstrainedWindow() { gtk_widget_show_all(border_.get()); // We collaborate with TabContentsViewGtk and stick ourselves in the // TabContentsViewGtk's floating container. ContainingView()->AttachConstrainedWindow(this); -} -ConstrainedWindowGtk::~ConstrainedWindowGtk() { - border_.Destroy(); + visible_ = true; } void ConstrainedWindowGtk::CloseConstrainedWindow() { - ContainingView()->RemoveConstrainedWindow(this); + if (visible_) + ContainingView()->RemoveConstrainedWindow(this); delegate_->DeleteDelegate(); owner_->WillClose(this); diff --git a/chrome/browser/gtk/constrained_window_gtk.h b/chrome/browser/gtk/constrained_window_gtk.h index f3ad8ec..fdfedf1 100644 --- a/chrome/browser/gtk/constrained_window_gtk.h +++ b/chrome/browser/gtk/constrained_window_gtk.h @@ -35,6 +35,7 @@ class ConstrainedWindowGtk : public ConstrainedWindow { virtual ~ConstrainedWindowGtk(); // Overridden from ConstrainedWindow: + virtual void ShowConstrainedWindow(); virtual void CloseConstrainedWindow(); // Returns the TabContents that constrains this Constrained Window. @@ -61,6 +62,9 @@ class ConstrainedWindowGtk : public ConstrainedWindow { // Delegate that provides the contents of this constrained window. ConstrainedWindowGtkDelegate* delegate_; + // Stores if |ShowConstrainedWindow()| has been called. + bool visible_; + DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowGtk); }; diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc index 501ecef..762f285 100644 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc @@ -321,6 +321,17 @@ bool TabRendererGtk::is_pinned() const { return data_.pinned; } +void TabRendererGtk::SetBlocked(bool blocked) { + if (data_.blocked == blocked) + return; + data_.blocked = blocked; + // TODO(zelidrag) bug 32399: Make tabs pulse on Linux as well. +} + +bool TabRendererGtk::is_blocked() const { + return data_.blocked; +} + void TabRendererGtk::set_animating_pinned_change(bool value) { data_.animating_pinned_change = value; } diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.h b/chrome/browser/gtk/tabs/tab_renderer_gtk.h index 3114f05..0c50f12 100644 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.h +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.h @@ -104,6 +104,10 @@ class TabRendererGtk : public AnimationDelegate { virtual void UpdateData(TabContents* contents, bool loading_only); // Sets the pinned state of the tab. + void SetBlocked(bool pinned); + bool is_blocked() const; + + // Sets the pinned state of the tab. void set_pinned(bool pinned); bool is_pinned() const; @@ -235,6 +239,7 @@ class TabRendererGtk : public AnimationDelegate { bool off_the_record; bool show_icon; bool pinned; + bool blocked; bool animating_pinned_change; }; diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index 0b5fa53..e27cdd7 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -954,6 +954,7 @@ void TabStripGtk::TabInsertedAt(TabContents* contents, tab->UpdateData(contents, false); } tab->set_pinned(model_->IsTabPinned(index)); + tab->SetBlocked(model_->IsTabBlocked(index)); if (gtk_widget_get_parent(tab->widget()) != tabstrip_.get()) gtk_fixed_put(GTK_FIXED(tabstrip_.get()), tab->widget(), 0, 0); @@ -1009,6 +1010,7 @@ void TabStripGtk::TabMoved(TabContents* contents, tab_data_.erase(tab_data_.begin() + from_index); TabData data = {tab, gfx::Rect()}; tab->set_pinned(model_->IsTabPinned(to_index)); + tab->SetBlocked(model_->IsTabBlocked(to_index)); tab_data_.insert(tab_data_.begin() + to_index, data); if (pinned_state_changed) { StartPinAndMoveTabAnimation(from_index, to_index, start_bounds); @@ -1038,6 +1040,11 @@ void TabStripGtk::TabPinnedStateChanged(TabContents* contents, int index) { StartPinnedTabAnimation(index); } +void TabStripGtk::TabBlockedStateChanged(TabContents* contents, int index) { + GetTabAt(index)->SetBlocked(model_->IsTabBlocked(index)); +} + + //////////////////////////////////////////////////////////////////////////////// // TabStripGtk, TabGtk::TabDelegate implementation: diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h index 082f616..4533e7a 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.h +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h @@ -107,6 +107,8 @@ class TabStripGtk : public TabStripModelObserver, virtual void TabChangedAt(TabContents* contents, int index, TabChangeType change_type); virtual void TabPinnedStateChanged(TabContents* contents, int index); + virtual void TabBlockedStateChanged(TabContents* contents, + int index); // TabGtk::TabDelegate implementation: virtual bool IsTabSelected(const TabGtk* tab) const; diff --git a/chrome/browser/login_prompt_gtk.cc b/chrome/browser/login_prompt_gtk.cc index 42f705c..272bd8f 100644 --- a/chrome/browser/login_prompt_gtk.cc +++ b/chrome/browser/login_prompt_gtk.cc @@ -106,17 +106,20 @@ class LoginHandlerGtk : public LoginHandler, GtkWidget* hbox = gtk_hbox_new(FALSE, 12); gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0); - GtkWidget* ok = gtk_button_new_from_stock(GTK_STOCK_OK); + ok_ = gtk_button_new_from_stock(GTK_STOCK_OK); gtk_button_set_label( - GTK_BUTTON(ok), + GTK_BUTTON(ok_), l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL).c_str()); - g_signal_connect(ok, "clicked", G_CALLBACK(OnOKClicked), this); - gtk_box_pack_end(GTK_BOX(hbox), ok, FALSE, FALSE, 0); + g_signal_connect(ok_, "clicked", G_CALLBACK(OnOKClicked), this); + gtk_box_pack_end(GTK_BOX(hbox), ok_, FALSE, FALSE, 0); GtkWidget* cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelClicked), this); gtk_box_pack_end(GTK_BOX(hbox), cancel, FALSE, FALSE, 0); + g_signal_connect(root_.get(), "hierarchy-changed", + G_CALLBACK(OnPromptShown), this); + SetModel(manager); // Scary thread safety note: This can potentially be called *after* SetAuth @@ -128,8 +131,8 @@ class LoginHandlerGtk : public LoginHandler, // Now that we have attached ourself to the window, we can make our OK // button the default action and mess with the focus. - GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); - gtk_widget_grab_default(ok); + GTK_WIDGET_SET_FLAGS(ok_, GTK_CAN_DEFAULT); + gtk_widget_grab_default(ok_); gtk_widget_grab_focus(username_entry_); SendNotifications(); @@ -305,6 +308,20 @@ class LoginHandlerGtk : public LoginHandler, handler->CancelAuth(); } + static void OnPromptShown(GtkButton* root, + GtkWidget* previous_toplevel, + LoginHandlerGtk* handler) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(handler->ok_))) + return; + + // Now that we have attached ourself to the window, we can make our OK + // button the default action and mess with the focus. + GTK_WIDGET_SET_FLAGS(handler->ok_, GTK_CAN_DEFAULT); + gtk_widget_grab_default(handler->ok_); + gtk_widget_grab_focus(handler->username_entry_); +} + // True if we've handled auth (SetAuth or CancelAuth has been called). bool handled_auth_; Lock handled_auth_lock_; @@ -339,6 +356,7 @@ class LoginHandlerGtk : public LoginHandler, // GtkEntry widgets that the user types into. GtkWidget* username_entry_; GtkWidget* password_entry_; + GtkWidget* ok_; // If not null, points to a model we need to notify of our own destruction // so it doesn't try and access this when its too late. diff --git a/chrome/browser/login_prompt_win.cc b/chrome/browser/login_prompt_win.cc index 72d4658..500c414 100644 --- a/chrome/browser/login_prompt_win.cc +++ b/chrome/browser/login_prompt_win.cc @@ -7,6 +7,8 @@ #include "app/l10n_util.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/password_manager/password_manager.h" +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/tab_contents.h" @@ -62,6 +64,9 @@ class LoginHandlerWin : public LoginHandler, virtual void WindowClosing() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + GetTabContentsForLogin()-> + render_view_host()->set_ignore_input_events(false); + // Reference is no longer valid. dialog_ = NULL; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 842e7b4..9a6c128 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1664,6 +1664,11 @@ void RenderViewHost::ForwardMouseEvent( case WebInputEvent::MouseLeave: view->HandleMouseLeave(); break; + case WebInputEvent::MouseDown: + case WebInputEvent::MouseWheel: + if (ignore_input_events() && delegate_) + delegate_->OnIgnoredUIEvent(); + break; default: // For now, we don't care about the rest. break; @@ -1671,6 +1676,16 @@ void RenderViewHost::ForwardMouseEvent( } } +void RenderViewHost::ForwardKeyboardEvent( + const NativeWebKeyboardEvent& key_event) { + if (ignore_input_events()) { + if (key_event.type == WebInputEvent::RawKeyDown && delegate_) + delegate_->OnIgnoredUIEvent(); + return; + } + RenderWidgetHost::ForwardKeyboardEvent(key_event); +} + void RenderViewHost::ForwardEditCommand(const std::string& name, const std::string& value) { IPC::Message* message = new ViewMsg_ExecuteEditCommand(routing_id(), diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 831bd80..8dcec74 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -415,6 +415,7 @@ class RenderViewHost : public RenderWidgetHost, virtual void GotFocus(); virtual bool CanBlur() const; virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event); + virtual void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event); virtual void ForwardEditCommand(const std::string& name, const std::string& value); virtual void ForwardEditCommandsForNextKeyEvent( diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index c3df62d..411840a 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -537,6 +537,12 @@ class RenderViewHostDelegate { // associated with the owning render view host. virtual WebPreferences GetWebkitPrefs(); + // Notification from the renderer host that blocked UI event occurred. + // This happens when there are tab-modal dialogs. In this case, the + // notification is needed to let us draw attention to the dialog (i.e. + // refocus on the modal dialog, flash title etc). + virtual void OnIgnoredUIEvent() {} + // Notification from the renderer that JS runs out of memory. virtual void OnJSOutOfMemory() {} diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 4798516..a721231 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -70,6 +70,7 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, is_unresponsive_(false), in_get_backing_store_(false), view_being_painted_(false), + ignore_input_events_(false), text_direction_updated_(false), text_direction_(WebKit::WebTextDirectionLeftToRight), text_direction_canceled_(false), @@ -351,7 +352,7 @@ void RenderWidgetHost::SystemThemeChanged() { } void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) { - if (process_->ignore_input_events()) + if (ignore_input_events_ || process_->ignore_input_events()) return; // Avoid spamming the renderer with mouse move events. It is important @@ -373,7 +374,7 @@ void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) { void RenderWidgetHost::ForwardWheelEvent( const WebMouseWheelEvent& wheel_event) { - if (process_->ignore_input_events()) + if (ignore_input_events_ || process_->ignore_input_events()) return; ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false); @@ -381,7 +382,7 @@ void RenderWidgetHost::ForwardWheelEvent( void RenderWidgetHost::ForwardKeyboardEvent( const NativeWebKeyboardEvent& key_event) { - if (process_->ignore_input_events()) + if (ignore_input_events_ || process_->ignore_input_events()) return; if (key_event.type == WebKeyboardEvent::Char && diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index ddda002..1291f72 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -248,7 +248,7 @@ class RenderWidgetHost : public IPC::Channel::Listener, // when it has received a message. virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event); void ForwardWheelEvent(const WebKit::WebMouseWheelEvent& wheel_event); - void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event); + virtual void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event); virtual void ForwardEditCommand(const std::string& name, const std::string& value); virtual void ForwardEditCommandsForNextKeyEvent( @@ -348,6 +348,13 @@ class RenderWidgetHost : public IPC::Channel::Listener, // Sets the active state (i.e., control tints). virtual void SetActive(bool active); + void set_ignore_input_events(bool ignore_input_events) { + ignore_input_events_ = ignore_input_events; + } + bool ignore_input_events() const { + return ignore_input_events_; + } + protected: // Internal implementation of the public Forward*Event() methods. void ForwardInputEvent(const WebKit::WebInputEvent& input_event, @@ -551,6 +558,9 @@ class RenderWidgetHost : public IPC::Channel::Listener, // back to whatever unhandled handler instead of the returned version. KeyQueue key_queue_; + // Set to true if we shouldn't send input events from the render widget. + bool ignore_input_events_; + // Set when we update the text direction of the selected input element. bool text_direction_updated_; WebKit::WebTextDirection text_direction_; diff --git a/chrome/browser/tab_contents/constrained_window.h b/chrome/browser/tab_contents/constrained_window.h index 057ee27..0eaec2a 100644 --- a/chrome/browser/tab_contents/constrained_window.h +++ b/chrome/browser/tab_contents/constrained_window.h @@ -39,8 +39,15 @@ class ConstrainedWindow { TabContents* owner, ConstrainedWindowDelegate* delegate); + // Makes the Constrained Window visible. Only one Constrained Window is shown + // at a time per tab. + virtual void ShowConstrainedWindow() = 0; + // Closes the Constrained Window. virtual void CloseConstrainedWindow() = 0; + + // Sets focus on the Constrained Window. + virtual void FocusConstrainedWindow() {} }; #endif // CHROME_BROWSER_TAB_CONTENTS_CONSTRAINED_WINDOW_H_ diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 097cb37..fdfa5ab 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -331,8 +331,10 @@ TabContents::~TabContents() { int size = static_cast<int>(child_windows_.size()); for (int i = size - 1; i >= 0; --i) { ConstrainedWindow* window = child_windows_[i]; - if (window) + if (window) { window->CloseConstrainedWindow(); + BlockTabContent(false); + } } if (blocked_popups_) @@ -767,9 +769,21 @@ ConstrainedWindow* TabContents::CreateConstrainedDialog( ConstrainedWindow* window = ConstrainedWindow::CreateConstrainedDialog(this, delegate); child_windows_.push_back(window); + + if (child_windows_.size() == 1) { + window->ShowConstrainedWindow(); + BlockTabContent(true); + } + return window; } +void TabContents::BlockTabContent(bool blocked) { + render_view_host()->set_ignore_input_events(blocked); + if (delegate_) + delegate_->SetTabContentBlocked(this, blocked); +} + void TabContents::AddNewContents(TabContents* new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, @@ -1003,8 +1017,15 @@ void TabContents::OnStartDownload(DownloadItem* download) { void TabContents::WillClose(ConstrainedWindow* window) { ConstrainedWindowList::iterator it = find(child_windows_.begin(), child_windows_.end(), window); + bool removed_topmost_window = it == child_windows_.begin(); if (it != child_windows_.end()) child_windows_.erase(it); + if (removed_topmost_window && child_windows_.size() > 0) { + child_windows_[0]->ShowConstrainedWindow(); + BlockTabContent(true); + } else { + BlockTabContent(false); + } } void TabContents::WillCloseBlockedPopupContainer( @@ -1404,8 +1425,11 @@ void TabContents::MaybeCloseChildWindows(const GURL& previous_url, int size = static_cast<int>(child_windows_.size()); for (int i = size - 1; i >= 0; --i) { ConstrainedWindow* window = child_windows_[i]; - if (window) + if (window) { + DCHECK(delegate_); window->CloseConstrainedWindow(); + BlockTabContent(false); + } } // Close the popup container. @@ -2406,6 +2430,13 @@ WebPreferences TabContents::GetWebkitPrefs() { return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, is_dom_ui); } +void TabContents::OnIgnoredUIEvent() { + if (constrained_window_count()) { + ConstrainedWindow* window = *constrained_window_begin(); + window->FocusConstrainedWindow(); + } +} + void TabContents::OnJSOutOfMemory() { AddInfoBar(new SimpleAlertInfoBarDelegate( this, l10n_util::GetString(IDS_JS_OUT_OF_MEMORY_PROMPT), NULL)); diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 112675d..de1e3ab 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -7,6 +7,7 @@ #include "build/build_config.h" +#include <deque> #include <map> #include <set> #include <string> @@ -348,9 +349,8 @@ class TabContents : public PageNavigator, // Create a new window constrained to this TabContents' clip and visibility. // The window is initialized by using the supplied delegate to obtain basic - // window characteristics, and the supplied view for the content. The window - // is sized according to the preferred size of the content_view, and centered - // within the contents. + // window characteristics, and the supplied view for the content. Note that + // the returned ConstrainedWindow might not yet be visible. ConstrainedWindow* CreateConstrainedDialog( ConstrainedWindowDelegate* delegate); @@ -379,7 +379,7 @@ class TabContents : public PageNavigator, // Returns the number of constrained windows in this tab. Used by tests. size_t constrained_window_count() { return child_windows_.size(); } - typedef std::vector<ConstrainedWindow*> ConstrainedWindowList; + typedef std::deque<ConstrainedWindow*> ConstrainedWindowList; // Return an iterator for the first constrained window in this tab contents. ConstrainedWindowList::iterator constrained_window_begin() @@ -912,6 +912,7 @@ class TabContents : public PageNavigator, virtual GURL GetAlternateErrorPageURL() const; virtual RendererPreferences GetRendererPrefs(Profile* profile) const; virtual WebPreferences GetWebkitPrefs(); + virtual void OnIgnoredUIEvent(); virtual void OnJSOutOfMemory(); virtual void OnCrossSiteResponse(int new_render_process_host_id, int new_request_id); @@ -935,6 +936,9 @@ class TabContents : public PageNavigator, // RenderViewHostManager::Delegate ------------------------------------------- + // Blocks/unblocks interaction with renderer process. + void BlockTabContent(bool blocked); + virtual void BeforeUnloadFiredFromRenderManager( bool proceed, bool* proceed_to_fire_unload); diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h index 817bd25..9cdd2cc 100644 --- a/chrome/browser/tab_contents/tab_contents_delegate.h +++ b/chrome/browser/tab_contents/tab_contents_delegate.h @@ -183,6 +183,12 @@ class TabContentsDelegate { return false; } + // Changes the blocked state of the tab at |index|. TabContents are + // considered blocked while displaying a tab modal dialog. During that time + // renderer host will ignore any UI interaction within TabContent outside of + // the currently displaying dialog. + virtual void SetTabContentBlocked(TabContents* contents, bool blocked) { } + // Notification that |tab_contents| has gained focus. virtual void TabContentsFocused(TabContents* tab_content) { } diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc index 2c94b7d..a085ced 100644 --- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc @@ -112,7 +112,8 @@ TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents) : TabContentsView(tab_contents), floating_(gtk_floating_container_new()), expanded_(gtk_expanded_container_new()), - popup_view_(NULL) { + popup_view_(NULL), + constrained_window_(NULL) { gtk_widget_set_name(expanded_, "chrome-tab-contents-view"); g_signal_connect(expanded_, "size-allocate", G_CALLBACK(OnSizeAllocate), this); @@ -150,24 +151,20 @@ void TabContentsViewGtk::RemoveBlockedPopupView( void TabContentsViewGtk::AttachConstrainedWindow( ConstrainedWindowGtk* constrained_window) { - DCHECK(find(constrained_windows_.begin(), constrained_windows_.end(), - constrained_window) == constrained_windows_.end()); + DCHECK(constrained_window_ == NULL); - constrained_windows_.push_back(constrained_window); + constrained_window_ = constrained_window; gtk_floating_container_add_floating(GTK_FLOATING_CONTAINER(floating_.get()), constrained_window->widget()); } void TabContentsViewGtk::RemoveConstrainedWindow( ConstrainedWindowGtk* constrained_window) { - std::vector<ConstrainedWindowGtk*>::iterator item = - find(constrained_windows_.begin(), constrained_windows_.end(), - constrained_window); - DCHECK(item != constrained_windows_.end()); + DCHECK(constrained_window == constrained_window_); + constrained_window_ = NULL; gtk_container_remove(GTK_CONTAINER(floating_.get()), constrained_window->widget()); - constrained_windows_.erase(item); } void TabContentsViewGtk::CreateView(const gfx::Size& initial_size) { @@ -422,12 +419,8 @@ void TabContentsViewGtk::OnSetFloatingPosition( // Place each ConstrainedWindow in the center of the view. int half_view_width = std::max((allocation->x + allocation->width) / 2, 0); int half_view_height = std::max((allocation->y + allocation->height) / 2, 0); - std::vector<ConstrainedWindowGtk*>::iterator it = - tab_contents_view->constrained_windows_.begin(); - std::vector<ConstrainedWindowGtk*>::iterator end = - tab_contents_view->constrained_windows_.end(); - for (; it != end; ++it) { - GtkWidget* widget = (*it)->widget(); + if (tab_contents_view->constrained_window_) { + GtkWidget* widget = tab_contents_view->constrained_window_->widget(); DCHECK(widget->parent == tab_contents_view->floating_.get()); GtkRequisition requisition; diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h index 5b1d820..0c84e1e 100644 --- a/chrome/browser/tab_contents/tab_contents_view_gtk.h +++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h @@ -7,8 +7,6 @@ #include <gtk/gtk.h> -#include <vector> - #include "base/scoped_ptr.h" #include "chrome/browser/gtk/focus_store_gtk.h" #include "chrome/browser/tab_contents/tab_contents_view.h" @@ -133,9 +131,9 @@ class TabContentsViewGtk : public TabContentsView, // opened). |popup_view_| is owned by the TabContents, not the view. BlockedPopupContainerViewGtk* popup_view_; - // Each individual UI for constrained dialogs currently displayed. The - // objects in this vector are owned by the TabContents, not the view. - std::vector<ConstrainedWindowGtk*> constrained_windows_; + // The UI for the constrained dialog currently displayed. This is owned by + // TabContents, not the view. + ConstrainedWindowGtk* constrained_window_; // The helper object that handles drag destination related interactions with // GTK. diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc index 783e27c..56ec106 100644 --- a/chrome/browser/tabs/tab_strip_model.cc +++ b/chrome/browser/tabs/tab_strip_model.cc @@ -342,6 +342,16 @@ bool TabStripModel::ShouldResetGroupOnSelect(TabContents* contents) const { return contents_data_.at(index)->reset_group_on_select; } +void TabStripModel::SetTabBlocked(int index, bool blocked) { + DCHECK(ContainsIndex(index)); + if (contents_data_[index]->blocked == blocked) + return; + contents_data_[index]->blocked = blocked; + FOR_EACH_OBSERVER(TabStripModelObserver, observers_, + TabBlockedStateChanged(contents_data_[index]->contents, + index)); +} + void TabStripModel::SetTabPinned(int index, bool pinned) { DCHECK(ContainsIndex(index)); if (contents_data_[index]->pinned == pinned) @@ -373,6 +383,10 @@ bool TabStripModel::IsTabPinned(int index) const { return contents_data_[index]->pinned; } +bool TabStripModel::IsTabBlocked(int index) const { + return contents_data_[index]->blocked; +} + int TabStripModel::IndexOfFirstNonPinnedTab() const { for (size_t i = 0; i < contents_data_.size(); ++i) { if (!contents_data_[i]->pinned) diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h index fe94524..bdd92c3 100644 --- a/chrome/browser/tabs/tab_strip_model.h +++ b/chrome/browser/tabs/tab_strip_model.h @@ -105,6 +105,11 @@ class TabStripModelObserver { // notified by way of the TabMoved method with |pinned_state_changed| true. virtual void TabPinnedStateChanged(TabContents* contents, int index) { } + // Invoked when the blocked state of a tab changes. + // NOTE: This is invoked when a tab becomes blocked/unblocked by a tab modal + // window. + virtual void TabBlockedStateChanged(TabContents* contents, int index) { } + // The TabStripModel now no longer has any "significant" (user created or // user manipulated) tabs. The implementer may use this as a trigger to try // and close the window containing the TabStripModel, for example... @@ -419,6 +424,9 @@ class TabStripModel : public NotificationObserver { // should be reset when _any_ selection change occurs in the model. bool ShouldResetGroupOnSelect(TabContents* contents) const; + // Changes the blocked state of the tab at |index|. + void SetTabBlocked(int index, bool blocked); + // Changes the pinned state of the tab at |index|. See description above // class for details on this. void SetTabPinned(int index, bool pinned); @@ -426,6 +434,9 @@ class TabStripModel : public NotificationObserver { // Returns true if the tab at |index| is pinned. bool IsTabPinned(int index) const; + // Returns true if the tab at |index| is blocked by a tab modal dialog. + bool IsTabBlocked(int index) const; + // Returns the index of the first tab that is not pinned. This returns // |count()| if all of the tabs are pinned, and 0 if no tabs are pinned. int IndexOfFirstNonPinnedTab() const; @@ -568,7 +579,8 @@ class TabStripModel : public NotificationObserver { explicit TabContentsData(TabContents* a_contents) : contents(a_contents), reset_group_on_select(false), - pinned(false) { + pinned(false), + blocked(false) { SetGroup(NULL); } @@ -612,6 +624,9 @@ class TabStripModel : public NotificationObserver { // Is the tab pinned? bool pinned; + + // Is the tab interaction blocked by a modal dialog? + bool blocked; }; // The TabContents data currently hosted within this TabStripModel. diff --git a/chrome/browser/views/constrained_window_win.cc b/chrome/browser/views/constrained_window_win.cc index c94576e..e0ff52e 100644 --- a/chrome/browser/views/constrained_window_win.cc +++ b/chrome/browser/views/constrained_window_win.cc @@ -592,6 +592,16 @@ views::NonClientFrameView* ConstrainedWindowWin::CreateFrameViewForWindow() { return new ConstrainedWindowFrameView(this); } +void ConstrainedWindowWin::FocusConstrainedWindow() { + focused_view_->RequestFocus(); +} + +void ConstrainedWindowWin::ShowConstrainedWindow() { + ActivateConstrainedWindow(); + FocusConstrainedWindow(); +} + + void ConstrainedWindowWin::CloseConstrainedWindow() { // Broadcast to all observers of NOTIFY_CWINDOW_CLOSED. // One example of such an observer is AutomationCWindowTracker in the @@ -632,7 +642,9 @@ ConstrainedWindowWin::ConstrainedWindowWin( set_focus_on_creation(false); WindowWin::Init(owner_->GetNativeView(), gfx::Rect()); - ActivateConstrainedWindow(); + + focused_view_ = window_delegate->GetContentsView(); + DCHECK(focused_view_); } void ConstrainedWindowWin::ActivateConstrainedWindow() { diff --git a/chrome/browser/views/constrained_window_win.h b/chrome/browser/views/constrained_window_win.h index d51dc8e..d5e3022 100644 --- a/chrome/browser/views/constrained_window_win.h +++ b/chrome/browser/views/constrained_window_win.h @@ -35,7 +35,9 @@ class ConstrainedWindowWin : public ConstrainedWindow, virtual views::NonClientFrameView* CreateFrameViewForWindow(); // Overridden from ConstrainedWindow: + virtual void ShowConstrainedWindow(); virtual void CloseConstrainedWindow(); + virtual void FocusConstrainedWindow(); virtual std::wstring GetWindowTitle() const; virtual const gfx::Rect& GetCurrentBounds() const; @@ -68,6 +70,7 @@ class ConstrainedWindowWin : public ConstrainedWindow, // Current display rectangle (relative to owner_'s visible area). gfx::Rect current_bounds_; + views::View* focused_view_; DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowWin); }; diff --git a/chrome/browser/views/login_view.cc b/chrome/browser/views/login_view.cc index 1682965..8564c2d 100644 --- a/chrome/browser/views/login_view.cc +++ b/chrome/browser/views/login_view.cc @@ -97,6 +97,12 @@ void LoginView::SetModel(LoginModel* model) { if (login_model_) login_model_->SetObserver(this); } + +void LoginView::RequestFocus() { + MessageLoop::current()->PostTask(FROM_HERE, + focus_grabber_factory_.NewRunnableMethod(&LoginView::FocusFirstField)); +} + /////////////////////////////////////////////////////////////////////////////// // LoginView, views::View, views::LoginModelObserver overrides: diff --git a/chrome/browser/views/login_view.h b/chrome/browser/views/login_view.h index 330ff32..01b1b7c 100644 --- a/chrome/browser/views/login_view.h +++ b/chrome/browser/views/login_view.h @@ -36,6 +36,8 @@ class LoginView : public views::View, public LoginModelObserver { // of the caller to inform this view if the model is deleted. void SetModel(LoginModel* model); + virtual void RequestFocus(); + protected: // views::View overrides: virtual void ViewHierarchyChanged(bool is_add, views::View *parent, diff --git a/chrome/browser/views/tabs/tab_renderer.cc b/chrome/browser/views/tabs/tab_renderer.cc index 8d5a4a3..8f6018c 100644 --- a/chrome/browser/views/tabs/tab_renderer.cc +++ b/chrome/browser/views/tabs/tab_renderer.cc @@ -893,3 +893,14 @@ void TabRenderer::LoadTabImages() { loading_animation_frames = rb.GetBitmapNamed(IDR_THROBBER); waiting_animation_frames = rb.GetBitmapNamed(IDR_THROBBER_WAITING); } + +void TabRenderer::SetBlocked(bool blocked) { + if (data_.blocked == blocked) + return; + data_.blocked = blocked; + if (blocked) + StartPulse(); + else + StopPulse(); +} + diff --git a/chrome/browser/views/tabs/tab_renderer.h b/chrome/browser/views/tabs/tab_renderer.h index bf71dfc..4cecfbe 100644 --- a/chrome/browser/views/tabs/tab_renderer.h +++ b/chrome/browser/views/tabs/tab_renderer.h @@ -48,6 +48,10 @@ class TabRenderer : public views::View, void UpdateData(TabContents* contents, bool loading_only); // Sets the pinned state of the tab. + void SetBlocked(bool blocked); + bool blocked() const { return data_.blocked; } + + // Sets the pinned state of the tab. void set_pinned(bool pinned) { data_.pinned = pinned; } bool pinned() const { return data_.pinned; } @@ -201,6 +205,7 @@ class TabRenderer : public views::View, bool off_the_record; bool show_icon; bool pinned; + bool blocked; bool animating_pinned_change; }; TabData data_; diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index e8838a7..248506a 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -1110,6 +1110,7 @@ void TabStrip::TabInsertedAt(TabContents* contents, tab->UpdateData(contents, false); } tab->set_pinned(model_->IsTabPinned(index)); + tab->SetBlocked(model_->IsTabBlocked(index)); // We only add the tab to the child list if it's not already - an invisible // tab maintained by the DraggedTabController will already be parented. @@ -1160,6 +1161,7 @@ void TabStrip::TabMoved(TabContents* contents, int from_index, int to_index, tab_data_.erase(tab_data_.begin() + from_index); TabData data = {tab, gfx::Rect()}; tab->set_pinned(model_->IsTabPinned(to_index)); + tab->SetBlocked(model_->IsTabBlocked(to_index)); tab_data_.insert(tab_data_.begin() + to_index, data); if (pinned_state_changed) { StartPinAndMoveTabAnimation(from_index, to_index, start_bounds); @@ -1189,6 +1191,10 @@ void TabStrip::TabPinnedStateChanged(TabContents* contents, int index) { StartPinnedTabAnimation(index); } +void TabStrip::TabBlockedStateChanged(TabContents* contents, int index) { + GetTabAt(index)->SetBlocked(model_->IsTabBlocked(index)); +} + /////////////////////////////////////////////////////////////////////////////// // TabStrip, Tab::Delegate implementation: diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h index 8ef00c07..9ecece6 100644 --- a/chrome/browser/views/tabs/tab_strip.h +++ b/chrome/browser/views/tabs/tab_strip.h @@ -136,6 +136,7 @@ class TabStrip : public views::View, virtual void TabChangedAt(TabContents* contents, int index, TabChangeType change_type); virtual void TabPinnedStateChanged(TabContents* contents, int index); + virtual void TabBlockedStateChanged(TabContents* contents, int index); // Tab::Delegate implementation: virtual bool IsTabSelected(const Tab* tab) const; |