diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-04 01:29:24 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-04 01:29:24 +0000 |
commit | bfd3886dea49078beed60f12b2c98e180172a2e7 (patch) | |
tree | 8bf0efa36b74a03a5425cbccc4a4b46b9b8ce0b9 /chrome | |
parent | 57ecbe8836e353ba61860ca2f8ef2b6ddca75d6a (diff) | |
download | chromium_src-bfd3886dea49078beed60f12b2c98e180172a2e7.zip chromium_src-bfd3886dea49078beed60f12b2c98e180172a2e7.tar.gz chromium_src-bfd3886dea49078beed60f12b2c98e180172a2e7.tar.bz2 |
Revert change r4523 because Vista doesn't like it.
TBR=nsylvain
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4539 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
30 files changed, 1234 insertions, 772 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index cad0bfb..214da38 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3165,9 +3165,6 @@ each locale. --> <message name="IDS_POPUPS_BLOCKED_COUNT" desc="Message on the blocked popup window"> Pop-ups Blocked: <ph name="COUNT">$1<ex>2</ex></ph> </message> - <message name="IDS_POPUP_TITLE_FORMAT" desc="Order of URL - Title on the popup"> - <ph name="URL">$1</ph> - <ph name="Window Title">$2</ph> - </message> <!-- Multiple download warning--> <message name="IDS_MULTI_DOWNLOAD_WARNING" desc="Warning invoked if multiple downloads are attempted without user interaction."> diff --git a/chrome/app/theme/menu_droparrow.png b/chrome/app/theme/menu_droparrow.png Binary files differdeleted file mode 100644 index 9cc81e0..0000000 --- a/chrome/app/theme/menu_droparrow.png +++ /dev/null diff --git a/chrome/app/theme/theme_resources.h b/chrome/app/theme/theme_resources.h index e46c444..a4cba37 100644 --- a/chrome/app/theme/theme_resources.h +++ b/chrome/app/theme/theme_resources.h @@ -314,4 +314,3 @@ #define IDR_PRODUCT_LOGO 9306 #define IDR_DISTRIBUTOR_LOGO 9307 #define IDR_DISTRIBUTOR_LOGO_LIGHT 9308 -#define IDR_MENU_DROPARROW 9309 diff --git a/chrome/app/theme/theme_resources.rc b/chrome/app/theme/theme_resources.rc index abc8199..58c3e8b 100644 --- a/chrome/app/theme/theme_resources.rc +++ b/chrome/app/theme/theme_resources.rc @@ -303,4 +303,3 @@ IDR_FIND_DLG_RIGHT_BB_BACKGROUND BINDATA "find_dlg_right_bb_bg.png" IDR_FIND_DLG_MIDDLE_BB_BACKGROUND BINDATA "find_dlg_middle_bb_bg.png" IDR_THROBBER_LIGHT BINDATA "throbber_light.png" IDR_OTR_ICON_STANDALONE BINDATA "otr_icon_standalone.png" -IDR_MENU_DROPARROW BINDATA "menu_droparrow.png" diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 016b43b..dcb7082 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -732,6 +732,42 @@ void Browser::AddNewContents(TabContents* source, } } +void Browser::StartDraggingDetachedContents(TabContents* source, + TabContents* new_contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt, + int frame_component) { + if (!g_browser_process->IsUsingNewFrames()) { + BrowserType::Type new_type = BrowserType::BROWSER; + + // If this is a minimal chrome browser, propagate to detached contents to + // avoid having URL fields in popups. + if (type_ == BrowserType::APPLICATION) + new_type = type_; + + Browser* browser = new Browser(contents_bounds, SIZE_TO_CONTENTS, profile_, + new_type, L""); + browser->AddNewContents( + source, new_contents, NEW_FOREGROUND_TAB, contents_bounds, true); + browser->Show(); + browser->window_->ContinueDetachConstrainedWindowDrag( + mouse_pt, frame_component); + } else { + // If we're inside an application frame, preserve that type (i.e. don't + // show a location bar on the new window), otherwise open a tab-less + // browser window with a location bar. + BrowserType::Type new_type = + type_ == BrowserType::APPLICATION ? type_ : BrowserType::BROWSER; + Browser* browser = new Browser(contents_bounds, SW_SHOWNORMAL, profile_, + BrowserType::BROWSER, std::wstring()); + browser->AddNewContents(source, new_contents, + NEW_FOREGROUND_TAB, gfx::Rect(), true); + browser->Show(); + browser->window()->ContinueDetachConstrainedWindowDrag(mouse_pt, + frame_component); + } +} + void Browser::ActivateContents(TabContents* contents) { tabstrip_model_.SelectTabContentsAt( tabstrip_model_.GetIndexOfTabContents(contents), false); @@ -1841,3 +1877,4 @@ void Browser::FormatTitleForDisplay(std::wstring* title) { current_index = match_index; } } + diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 58e32d0..c1b7b53 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -273,6 +273,11 @@ class Browser : public TabStripModelDelegate, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); + virtual void StartDraggingDetachedContents(TabContents* source, + TabContents* new_contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt, + int frame_component); virtual void ActivateContents(TabContents* contents); virtual void LoadingStateChanged(TabContents* source); virtual void CloseContents(TabContents* source); @@ -617,3 +622,4 @@ class Browser : public TabStripModelDelegate, }; #endif // CHROME_BROWSER_BROWSER_H_ + diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index 6f0e6ec..4012ddf 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -92,6 +92,18 @@ class BrowserWindow { // TODO(beng): REMOVE virtual void ShowTabContents(TabContents* contents) {} + // Continue a drag gesture that began with a constrained window. When the + // user drags a constrained window such that their mouse pointer leaves the + // bounds of the constraining HWND, the window is detached and the drag + // gesture continues except for this top level frame. + // |mouse_pt| is the position of the cursor in screen coordinates. + // |frame_component| is the component returned by WM_NCHITTEST for |mouse_pt| + // on the constrained window. This is passed to ensure we initiate the + // correct action (move, resize, etc). + virtual void ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_pt, + int frame_component) = 0; + // Sizes the frame to match the specified desired bounds for the contents. // |contents_bounds| are in screen coordinates. // TODO(beng): REMOVE @@ -177,3 +189,4 @@ class BrowserWindow { }; #endif // CHROME_BROWSER_BROWSER_WINDOW_H__ + diff --git a/chrome/browser/constrained_window.h b/chrome/browser/constrained_window.h index d703ad2..04c0af9 100644 --- a/chrome/browser/constrained_window.h +++ b/chrome/browser/constrained_window.h @@ -21,6 +21,53 @@ class GURL; class TabContents; /////////////////////////////////////////////////////////////////////////////// +// ConstrainedTabContentsDelegate +// +// An object that implements this interface is managing one or more +// constrained windows. This interface is used to inform the delegate about +// events within the Constrained Window. +// +class ConstrainedTabContentsDelegate { + public: + // Called when the contained TabContents creates a new TabContents. The + // ConstrainedWindow has no way to present the new TabContents, so it just + // lets the delegate decide what to do. + virtual void AddNewContents(ConstrainedWindow* window, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) = 0; + + // Called to open a URL in a the specified manner. + virtual void OpenURL(ConstrainedWindow* window, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) = 0; + + // Called when the window is about to be closed. + virtual void WillClose(ConstrainedWindow* window) = 0; + + // Called when the window's contents should be detached into a top-level + // window. The delegate is expected to have re-parented the TabContents by + // the time this method returns. + // |contents_bounds| is the bounds of the TabContents after the detach + // action. These are in screen coordinates and are for the TabContents _only_ + // - the window UI should be created around it at an appropriate size. + // |mouse_pt| is the position of the cursor in screen coordinates. + // |frame_component| is the part of the constrained window frame that + // corresponds to |mouse_pt| as returned by WM_NCHITTEST. + virtual void DetachContents(ConstrainedWindow* window, + TabContents* contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt, + int frame_component) = 0; + + // Called when the window is moved or resized. + virtual void DidMoveOrResize(ConstrainedWindow* window) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// // ConstrainedWindow // // This interface represents a window that is constrained to a TabContents' @@ -40,6 +87,21 @@ class ConstrainedWindow { views::View* contents_view, views::WindowDelegate* window_delegate); + // Create a Constrained Window that contains a TabContents subclass, e.g. for + // a web popup. |initial_bounds| specifies the desired position of the + // |constrained_contents|, not the bounds of the window itself. + // |user_gesture| specifies whether or not this window was opened as a result + // of a user input event, or is an unsolicited popup. + static ConstrainedWindow* CreateConstrainedPopup( + TabContents* owner, + const gfx::Rect& initial_bounds, + TabContents* constrained_contents); + + // Activates the Constrained Window, which has the effect of detaching it if + // it contains a WebContents, otherwise just brings it to the front of the + // z-order. + virtual void ActivateConstrainedWindow() = 0; + // Closes the Constrained Window. virtual void CloseConstrainedWindow() = 0; @@ -48,6 +110,11 @@ class ConstrainedWindow { virtual void RepositionConstrainedWindowTo( const gfx::Point& anchor_point) = 0; + // Returns true if the Constrained Window is being "suppressed" (i.e. + // positioned to the bottom right of the constraining TabContents) because it + // was opened without a user gesture. + virtual bool IsSuppressedConstrainedWindow() const = 0; + // Tells the Constrained Window that the constraining TabContents was hidden, // e.g. via a tab switch. virtual void WasHidden() = 0; @@ -59,6 +126,9 @@ class ConstrainedWindow { // Returns the title of the Constrained Window. virtual std::wstring GetWindowTitle() const = 0; + // Updates the Window's title and repaints the titlebar + virtual void UpdateWindowTitle() = 0; + // Returns the current display rectangle (relative to its // parent). This method is only called from the unit tests to check // the location/size of a constrained window. @@ -66,3 +136,4 @@ class ConstrainedWindow { }; #endif // #ifndef CHROME_BROWSER_CONSTRAINED_WINDOW_H__ + diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc index ea1f7e3..c97d15d 100644 --- a/chrome/browser/external_tab_container.cc +++ b/chrome/browser/external_tab_container.cc @@ -170,6 +170,13 @@ void ExternalTabContainer::AddNewContents(TabContents* source, bool user_gesture) { } +void ExternalTabContainer::StartDraggingDetachedContents( + TabContents* source, + TabContents* new_contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt) { +} + void ExternalTabContainer::ActivateContents(TabContents* contents) { } @@ -329,3 +336,4 @@ ExternalTabContainer* ExternalTabContainer::GetContainerForTab( GetProp(parent_window, kWindowObjectKey)); return container; } + diff --git a/chrome/browser/external_tab_container.h b/chrome/browser/external_tab_container.h index bb8b21f..1f694a0 100644 --- a/chrome/browser/external_tab_container.h +++ b/chrome/browser/external_tab_container.h @@ -66,6 +66,10 @@ class ExternalTabContainer : public TabContentsDelegate, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); + virtual void StartDraggingDetachedContents(TabContents* source, + TabContents* new_contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt); virtual void ActivateContents(TabContents* contents); virtual void LoadingStateChanged(TabContents* source); virtual void CloseContents(TabContents* source); @@ -143,3 +147,4 @@ class ExternalTabContainer : public TabContentsDelegate, }; #endif // CHROME_BROWSER_EXTERNAL_TAB_CONTAINER_H__ + diff --git a/chrome/browser/tab_contents.cc b/chrome/browser/tab_contents.cc index 0215ec7..931d415 100644 --- a/chrome/browser/tab_contents.cc +++ b/chrome/browser/tab_contents.cc @@ -8,7 +8,6 @@ #include "chrome/browser/navigation_entry.h" #include "chrome/browser/views/download_shelf_view.h" #include "chrome/browser/views/download_started_animation.h" -#include "chrome/browser/views/blocked_popup_container.h" #include "chrome/browser/web_contents.h" #include "chrome/browser/tab_contents_delegate.h" #include "chrome/common/l10n_util.h" @@ -44,7 +43,6 @@ TabContents::TabContents(TabContentsType type) saved_location_bar_state_(NULL), shelf_visible_(false), max_page_id_(-1), - blocked_popups_(NULL), capturing_contents_(false) { last_focused_view_storage_id_ = views::ViewStorage::GetSharedInstance()->CreateStorageID(); @@ -292,25 +290,25 @@ void TabContents::AddNewContents(TabContents* new_contents, void TabContents::AddConstrainedPopup(TabContents* new_contents, const gfx::Rect& initial_pos) { - if (!blocked_popups_) { - CRect client_rect; - GetClientRect(GetContainerHWND(), &client_rect); - gfx::Point anchor_position( - client_rect.Width() - - views::NativeScrollBar::GetVerticalScrollBarWidth(), - client_rect.Height()); - - blocked_popups_ = BlockedPopupContainer::Create( - this, profile(), anchor_position); - child_windows_.push_back(blocked_popups_); - } + ConstrainedWindow* window = + ConstrainedWindow::CreateConstrainedPopup( + this, initial_pos, new_contents); + child_windows_.push_back(window); - blocked_popups_->AddTabContents(new_contents, initial_pos); + CRect client_rect; + GetClientRect(GetContainerHWND(), &client_rect); + gfx::Size new_size(client_rect.Width(), client_rect.Height()); + RepositionSupressedPopupsToFit(new_size); } void TabContents::CloseAllSuppressedPopups() { - if (blocked_popups_) - blocked_popups_->CloseAllPopups(); + // Close all auto positioned child windows to "clean up" the workspace. + int count = static_cast<int>(child_windows_.size()); + for (int i = count - 1; i >= 0; --i) { + ConstrainedWindow* window = child_windows_.at(i); + if (window->IsSuppressedConstrainedWindow()) + window->CloseConstrainedWindow(); + } } void TabContents::Focus() { @@ -446,15 +444,28 @@ void TabContents::MigrateShelfViewFrom(TabContents* tab_contents) { tab_contents->ReleaseDownloadShelfView(); } +void TabContents::AddNewContents(ConstrainedWindow* window, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + AddNewContents(new_contents, disposition, initial_pos, user_gesture); +} + +void TabContents::OpenURL(ConstrainedWindow* window, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) { + OpenURL(url, referrer, disposition, transition); +} + void TabContents::WillClose(ConstrainedWindow* window) { ConstrainedWindowList::iterator it = find(child_windows_.begin(), child_windows_.end(), window); if (it != child_windows_.end()) child_windows_.erase(it); - if (window == blocked_popups_) - blocked_popups_ = NULL; - if (::IsWindow(GetContainerHWND())) { CRect client_rect; GetClientRect(GetContainerHWND(), &client_rect); @@ -463,6 +474,19 @@ void TabContents::WillClose(ConstrainedWindow* window) { } } +void TabContents::DetachContents(ConstrainedWindow* window, + TabContents* contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt, + int frame_component) { + WillClose(window); + if (delegate_) { + contents->DisassociateFromPopupCount(); + delegate_->StartDraggingDetachedContents( + this, contents, contents_bounds, mouse_pt, frame_component); + } +} + void TabContents::DidMoveOrResize(ConstrainedWindow* window) { UpdateWindow(GetContainerHWND()); } @@ -508,9 +532,12 @@ void TabContents::RepositionSupressedPopupsToFit(const gfx::Size& new_size) { new_size.width() - views::NativeScrollBar::GetVerticalScrollBarWidth(), new_size.height()); - - if (blocked_popups_) - blocked_popups_->RepositionConstrainedWindowTo(anchor_position); + int window_count = static_cast<int>(child_windows_.size()); + for (int i = window_count - 1; i >= 0; --i) { + ConstrainedWindow* window = child_windows_.at(i); + if (window->IsSuppressedConstrainedWindow()) + window->RepositionConstrainedWindowTo(anchor_position); + } } void TabContents::ReleaseDownloadShelfView() { diff --git a/chrome/browser/tab_contents.h b/chrome/browser/tab_contents.h index f4d981e..54a9e45 100644 --- a/chrome/browser/tab_contents.h +++ b/chrome/browser/tab_contents.h @@ -23,7 +23,6 @@ namespace views { class WindowDelegate; } -class BlockedPopupContainer; class DOMUIHost; class DownloadItem; class DownloadShelfView; @@ -53,7 +52,8 @@ class WebContents; // the NavigationController makes the active TabContents inactive, notifies the // TabContentsDelegate that the TabContents is being replaced, and then // activates the new TabContents. -class TabContents : public PageNavigator { +class TabContents : public PageNavigator, + public ConstrainedTabContentsDelegate { public: // Flags passed to the TabContentsDelegate.NavigationStateChanged to tell it // what has changed. Combine them to update more than one thing. @@ -411,11 +411,25 @@ class TabContents : public PageNavigator { // want to generalize this if we need to migrate some other state. static void MigrateShelfView(TabContents* from, TabContents* to); - // Called when a ConstrainedWindow we own is about to be closed. - void WillClose(ConstrainedWindow* window); + // ConstrainedTabContentsDelegate -------------------------------------------- - // Called when a ConstrainedWindow we own is moved or resized. - void DidMoveOrResize(ConstrainedWindow* window); + virtual void AddNewContents(ConstrainedWindow* window, + TabContents* contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture); + virtual void OpenURL(ConstrainedWindow* window, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition); + virtual void WillClose(ConstrainedWindow* window); + virtual void DetachContents(ConstrainedWindow* window, + TabContents* contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt, + int frame_component); + virtual void DidMoveOrResize(ConstrainedWindow* window); protected: friend class NavigationController; @@ -503,11 +517,6 @@ class TabContents : public PageNavigator { // See capturing_contents() above. bool capturing_contents_; - // ConstrainedWindow with additional methods for managing blocked - // popups. This pointer alsog goes in |child_windows_| for ownership, - // repositioning, etc. - BlockedPopupContainer* blocked_popups_; - DISALLOW_COPY_AND_ASSIGN(TabContents); }; diff --git a/chrome/browser/tab_contents_delegate.h b/chrome/browser/tab_contents_delegate.h index 2365757..401fe9e 100644 --- a/chrome/browser/tab_contents_delegate.h +++ b/chrome/browser/tab_contents_delegate.h @@ -59,6 +59,21 @@ class TabContentsDelegate : public PageNavigator { const gfx::Rect& initial_pos, bool user_gesture) = 0; + // Called when while dragging constrained TabContents, the mouse pointer + // moves outside the bounds of the constraining contents. The delegate can + // use this as an opportunity to continue the drag in a detached window. + // |contents_bounds| is the bounds of the constrained TabContents in screen + // coordinates. + // |mouse_pt| is the position of the mouse pointer in screen coordinates. + // |frame_component| is the part of the constrained window frame that + // corresponds to |mouse_pt| as returned by WM_NCHITTEST. + virtual void StartDraggingDetachedContents( + TabContents* source, + TabContents* new_contents, + const gfx::Rect& contents_bounds, + const gfx::Point& mouse_pt, + int frame_component) { } + // Selects the specified contents, bringing its container to the front. virtual void ActivateContents(TabContents* contents) = 0; @@ -145,3 +160,4 @@ class TabContentsDelegate : public PageNavigator { }; #endif // CHROME_BROWSER_TAB_CONTENTS_DELEGATE_H_ + diff --git a/chrome/browser/views/blocked_popup_container.cc b/chrome/browser/views/blocked_popup_container.cc deleted file mode 100644 index e69e859..0000000 --- a/chrome/browser/views/blocked_popup_container.cc +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright (c) 2008 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/views/blocked_popup_container.h" - -#include "chrome/app/theme/theme_resources.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/tab_contents.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/views/background.h" -#include "chrome/views/button.h" -#include "chrome/views/menu_button.h" -#include "chrome/views/menu.h" -#include "chrome/common/l10n_util.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/gfx/path.h" - -#include "generated_resources.h" - -#include <math.h> - -const int kNotifyMenuItem = -1; - -// A number larger than the internal popup count on the Renderer; meant for -// preventing a compromised renderer from exhausting GDI memory by spawning -// infinite windows. -const int kImpossibleNumberOfPopups = 30; - -// A small border around all widgets -const int kSmallPadding = 2; - -// The background color of the blocked popup notification -//static const SkColor kBackgroundColor = SkColorSetRGB(222, 234, 248); -static const SkColor kBackgroundColorTop = SkColorSetRGB(255, 242, 183); -static const SkColor kBackgroundColorBottom = SkColorSetRGB(250, 230, 145); - -// The border color of the blocked popup notification. This is the same as the -// border around the inside of the tab contents. -static const SkColor kBorderColor = SkColorSetRGB(190, 205, 223); -// Thickness of the border. -static const int kBorderSize = 1; - -// Duration of the showing/hiding animations. -static const int kShowAnimationDurationMS = 200; -static const int kHideAnimationDurationMS = 120; -static const int kFramerate = 25; - -// Rounded corner radius (in pixels) -static const int kBackgroundCornerRadius = 4; - -// Rounded corner definition for the -static const SkScalar kRoundedCornerRad[8] = { - // Top left corner - SkIntToScalar(kBackgroundCornerRadius), - SkIntToScalar(kBackgroundCornerRadius), - // Top right corner - SkIntToScalar(kBackgroundCornerRadius), - SkIntToScalar(kBackgroundCornerRadius), - // Bottom right corner - 0, - 0, - // Bottom left corner - 0, - 0 -}; - -//////////////////////////////////////////////////////////////////////////////// -// BlockedPopupContainerView -// -// The view presented to the user notifying them of the number of popups -// blocked. -// -class BlockedPopupContainerView : public views::View, - public views::BaseButton::ButtonListener, - public Menu::Delegate { - public: - explicit BlockedPopupContainerView(BlockedPopupContainer* container); - ~BlockedPopupContainerView(); - - // Sets the label on the menu button - void UpdatePopupCountLabel(); - - // Overridden from views::View: - virtual void Paint(ChromeCanvas* canvas); - virtual void Layout(); - virtual gfx::Size GetPreferredSize(); - - // Overridden from views::ButtonListener::ButtonPressed: - virtual void ButtonPressed(views::BaseButton* sender); - - // Overridden from Menu::Delegate: - virtual bool IsItemChecked(int id) const; - virtual void ExecuteCommand(int id); - - private: - // Our owner and HWND parent. - BlockedPopupContainer* container_; - - // The button which brings up the popup menu. - views::MenuButton* popup_count_label_; - - // Our "X" button. - views::Button* close_button_; - - /// Popup menu shown to user. - scoped_ptr<Menu> launch_menu_; -}; - -BlockedPopupContainerView::BlockedPopupContainerView( - BlockedPopupContainer* container) - : container_(container) { - ResourceBundle &rb = ResourceBundle::GetSharedInstance(); - - // Create a button with a multidigit number to reserve space. - popup_count_label_ = new views::MenuButton( - l10n_util::GetStringF(IDS_POPUPS_BLOCKED_COUNT, IntToWString(99)), - NULL, true); - popup_count_label_->SetTextAlignment(views::TextButton::ALIGN_CENTER); - popup_count_label_->SetListener(this, 1); - AddChildView(popup_count_label_); - - // For now, we steal the Find close button, since it looks OK. - close_button_ = new views::Button(); - close_button_->SetFocusable(true); - close_button_->SetImage(views::Button::BS_NORMAL, - rb.GetBitmapNamed(IDR_CLOSE_BAR)); - close_button_->SetImage(views::Button::BS_HOT, - rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); - close_button_->SetImage(views::Button::BS_PUSHED, - rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); - close_button_->SetListener(this, 0); - AddChildView(close_button_); - - SetBackground(views::Background::CreateStandardPanelBackground()); - UpdatePopupCountLabel(); -} - -BlockedPopupContainerView::~BlockedPopupContainerView() { -} - -void BlockedPopupContainerView::UpdatePopupCountLabel() { - popup_count_label_->SetText(container_->GetWindowTitle()); - Layout(); - SchedulePaint(); -} - -void BlockedPopupContainerView::Paint(ChromeCanvas* canvas) { - View::Paint(canvas); - // Draw the standard background - - SkRect rect; - rect.set(0, 0, SkIntToScalar(width()), SkIntToScalar(height())); - - // Draw the border - SkPaint border_paint; - border_paint.setFlags(SkPaint::kAntiAlias_Flag); - border_paint.setStyle(SkPaint::kStroke_Style); - border_paint.setColor(kBorderColor); - SkPath border_path; - border_path.addRoundRect(rect, kRoundedCornerRad, SkPath::kCW_Direction); - canvas->drawPath(border_path, border_paint); -} - -void BlockedPopupContainerView::Layout() { - gfx::Size panel_size = GetPreferredSize(); - gfx::Size button_size = close_button_->GetPreferredSize(); - gfx::Size sz = popup_count_label_->GetPreferredSize(); - - popup_count_label_->SetBounds(kSmallPadding, kSmallPadding, - sz.width(), - sz.height()); - - int close_button_padding = - static_cast<int>(ceil(panel_size.height() / 2.0) - - ceil(button_size.height() / 2.0)); - close_button_->SetBounds(width() - button_size.width() - close_button_padding, - close_button_padding, - button_size.width(), - button_size.height()); -} - -gfx::Size BlockedPopupContainerView::GetPreferredSize() { - gfx::Size prefsize = popup_count_label_->GetPreferredSize(); - prefsize.Enlarge(close_button_->GetPreferredSize().width(), 0); - // Add padding to all sides of the |popup_count_label_| except the right. - prefsize.Enlarge(kSmallPadding, 2 * kSmallPadding); - - // Add padding to the left and right side of |close_button_| equal to its - // horizontal/vertical spacing. - gfx::Size button_size = close_button_->GetPreferredSize(); - int close_button_padding = - static_cast<int>(ceil(prefsize.height() / 2.0) - - ceil(button_size.height() / 2.0)); - prefsize.Enlarge(2 * close_button_padding, 0); - - return prefsize; -} - -void BlockedPopupContainerView::ButtonPressed(views::BaseButton* sender) { - if (sender == popup_count_label_) { - // Menu goes here. - launch_menu_.reset(new Menu(this, Menu::TOPLEFT, container_->GetHWND())); - - int item_count = container_->GetTabContentsCount(); - for (int i = 0; i < item_count; ++i) { - std::wstring label = container_->GetDisplayStringForItem(i); - // We can't just use the index into container_ here because Menu reserves - // the value 0 as the nop command. - launch_menu_->AppendMenuItem(i + 1, label, Menu::NORMAL); - } - - launch_menu_->AppendSeparator(); - launch_menu_->AppendMenuItem( - kNotifyMenuItem, - l10n_util::GetString(IDS_OPTIONS_SHOWPOPUPBLOCKEDNOTIFICATION), - Menu::NORMAL); - - CPoint cursor_pos; - ::GetCursorPos(&cursor_pos); - launch_menu_->RunMenuAt(cursor_pos.x, cursor_pos.y); - } else if (sender == close_button_) { - container_->set_dismissed(); - container_->CloseAllPopups(); - } -} - -bool BlockedPopupContainerView::IsItemChecked(int id) const { - if (id == kNotifyMenuItem) - return container_->GetShowBlockedPopupNotification(); - - return false; -} - -void BlockedPopupContainerView::ExecuteCommand(int id) { - if (id == kNotifyMenuItem) { - container_->ToggleBlockedPopupNotification(); - } else { - // Decrement id since all index based commands have 1 added to them. (See - // ButtonPressed() for detail). - container_->LaunchPopupIndex(id - 1); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// BlockedPopupContainer - -// static -BlockedPopupContainer* BlockedPopupContainer::Create( - TabContents* owner, Profile* profile, const gfx::Point& initial_anchor) { - BlockedPopupContainer* c = new BlockedPopupContainer(owner, profile); - c->Init(initial_anchor); - return c; -} - -BlockedPopupContainer::~BlockedPopupContainer() { -} - -BlockedPopupContainer::BlockedPopupContainer(TabContents* owner, - Profile* profile) - : Animation(kFramerate, NULL), - owner_(owner), - container_view_(NULL), - has_been_dismissed_(false), - in_show_animation_(false), - visibility_percentage_(0) { - block_popup_pref_.Init( - prefs::kBlockPopups, profile->GetPrefs(), NULL); -} - -void BlockedPopupContainer::ToggleBlockedPopupNotification() { - bool current = block_popup_pref_.GetValue(); - block_popup_pref_.SetValue(!current); -} - -bool BlockedPopupContainer::GetShowBlockedPopupNotification() { - return ! block_popup_pref_.GetValue(); -} - -void BlockedPopupContainer::AddTabContents(TabContents* blocked_contents, - const gfx::Rect& bounds) { - if (has_been_dismissed_) { - // We simply bounce this popup without notice. - blocked_contents->CloseContents(); - return; - } - - if (blocked_popups_.size() > kImpossibleNumberOfPopups) { - blocked_contents->CloseContents(); - LOG(INFO) << "Warning: Renderer is sending more popups to us then should be" - " possible. Renderer compromised?"; - return; - } - - blocked_contents->set_delegate(this); - blocked_popups_.push_back(std::make_pair(blocked_contents, bounds)); - container_view_->UpdatePopupCountLabel(); - - ShowSelf(); -} - -void BlockedPopupContainer::LaunchPopupIndex(int index) { - if (static_cast<size_t>(index) < blocked_popups_.size()) { - TabContents* contents = blocked_popups_[index].first; - gfx::Rect bounds = blocked_popups_[index].second; - blocked_popups_.erase(blocked_popups_.begin() + index); - container_view_->UpdatePopupCountLabel(); - - contents->set_delegate(NULL); - contents->DisassociateFromPopupCount(); - - // Pass this TabContents back to our owner, forcing the window to be - // displayed since user_gesture is true. - owner_->AddNewContents(contents, NEW_POPUP, bounds, true); - } - - if (blocked_popups_.size() == 0) - CloseAllPopups(); -} - -int BlockedPopupContainer::GetTabContentsCount() const { - return blocked_popups_.size(); -} - -std::wstring BlockedPopupContainer::GetDisplayStringForItem(int index) { - const GURL& url = blocked_popups_[index].first->GetURL().GetOrigin(); - - std::wstring label = - l10n_util::GetStringF(IDS_POPUP_TITLE_FORMAT, - UTF8ToWide(url.possibly_invalid_spec()), - blocked_popups_[index].first->GetTitle()); - return label; -} - -void BlockedPopupContainer::CloseAllPopups() { - CloseEachTabContents(); - container_view_->UpdatePopupCountLabel(); - HideSelf(); -} - -///////////////////////////////////////////////////////////////////////////////// -// Override from ConstrainedWindow: - -void BlockedPopupContainer::CloseConstrainedWindow() { - CloseEachTabContents(); - - // Broadcast to all observers of NOTIFY_CWINDOW_CLOSED. - // One example of such an observer is AutomationCWindowTracker in the - // automation component. - NotificationService::current()->Notify(NOTIFY_CWINDOW_CLOSED, - Source<ConstrainedWindow>(this), - NotificationService::NoDetails()); - - Close(); -} - -void BlockedPopupContainer::RepositionConstrainedWindowTo( - const gfx::Point& anchor_point) { - anchor_point_ = anchor_point; - SetPosition(); -} - -std::wstring BlockedPopupContainer::GetWindowTitle() const { - return l10n_util::GetStringF(IDS_POPUPS_BLOCKED_COUNT, - IntToWString(GetTabContentsCount())); -} - -const gfx::Rect& BlockedPopupContainer::GetCurrentBounds() const { - return bounds_; -} - -///////////////////////////////////////////////////////////////////////////////// -// Override from TabContentsDelegate: -void BlockedPopupContainer::OpenURLFromTab(TabContents* source, - const GURL& url, const GURL& referrer, - WindowOpenDisposition disposition, - PageTransition::Type transition) { - owner_->OpenURL(url, referrer, disposition, transition); -} - -void BlockedPopupContainer::ReplaceContents(TabContents* source, - TabContents* new_contents) { - // Walk the vector to find the correct TabContents and replace it. - bool found = false; - gfx::Rect rect; - for (std::vector<std::pair<TabContents*, gfx::Rect> >::iterator it = - blocked_popups_.begin(); it != blocked_popups_.end(); ++it) { - if (it->first == source) { - rect = it->second; - found = true; - blocked_popups_.erase(it); - break; - } - } - - if (found) - blocked_popups_.push_back(std::make_pair(new_contents, rect)); -} - -void BlockedPopupContainer::AddNewContents(TabContents* source, - TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture) { - owner_->AddNewContents(new_contents, disposition, initial_pos, - user_gesture); -} - -void BlockedPopupContainer::CloseContents(TabContents* source) { - for (std::vector<std::pair<TabContents*, gfx::Rect> >::iterator it = - blocked_popups_.begin(); it != blocked_popups_.end(); ++it) { - if (it->first == source) { - blocked_popups_.erase(it); - break; - } - } - - if (blocked_popups_.size() == 0) - CloseAllPopups(); -} - -void BlockedPopupContainer::MoveContents(TabContents* source, - const gfx::Rect& pos) { - for (std::vector<std::pair<TabContents*, gfx::Rect> >::iterator it = - blocked_popups_.begin(); it != blocked_popups_.end(); ++it) { - if (it->first == source) { - it->second = pos; - break; - } - } -} - -bool BlockedPopupContainer::IsPopup(TabContents* source) { - return true; -} - -TabContents* BlockedPopupContainer::GetConstrainingContents( - TabContents* source) { - return owner_; -} - -///////////////////////////////////////////////////////////////////////////////// -// Override from Animation: -void BlockedPopupContainer::AnimateToState(double state) { - if (in_show_animation_) - visibility_percentage_ = state; - else - visibility_percentage_ = 1 - state; - - SetPosition(); -} - -///////////////////////////////////////////////////////////////////////////////// -// Override from views::ContainerWin: -void BlockedPopupContainer::OnFinalMessage(HWND window) { - owner_->WillClose(this); - CloseEachTabContents(); - ContainerWin::OnFinalMessage(window); -} - -void BlockedPopupContainer::OnSize(UINT param, const CSize& size) { - // Set the window region so we have rounded corners on the top. - SkRect rect; - rect.set(0, 0, SkIntToScalar(size.cx), SkIntToScalar(size.cy)); - gfx::Path path; - path.addRoundRect(rect, kRoundedCornerRad, SkPath::kCW_Direction); - SetWindowRgn(path.CreateHRGN(), TRUE); - - ChangeSize(param, size); -} - -// private: - -void BlockedPopupContainer::Init(const gfx::Point& initial_anchor) { - container_view_ = new BlockedPopupContainerView(this); - container_view_->SetVisible(true); - - set_window_style(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); - ContainerWin::Init(owner_->GetContainerHWND(), gfx::Rect(), false); - SetContentsView(container_view_); - RepositionConstrainedWindowTo(initial_anchor); - - if (GetShowBlockedPopupNotification()) - ShowSelf(); - else - has_been_dismissed_ = true; -} - -void BlockedPopupContainer::HideSelf() { - in_show_animation_ = false; - Animation::SetDuration(kHideAnimationDurationMS); - Animation::Start(); -} - -void BlockedPopupContainer::ShowSelf() { - SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - if (!Animation::IsAnimating() && visibility_percentage_ < 1.0) { - in_show_animation_ = true; - Animation::SetDuration(kShowAnimationDurationMS); - Animation::Start(); - } -} - -void BlockedPopupContainer::SetPosition() { - gfx::Size size = container_view_->GetPreferredSize(); - int base_x = anchor_point_.x() - size.width(); - int base_y = anchor_point_.y() - size.height(); - // The bounds we report through the automation system are the real bounds; - // the animation is short lived... - bounds_ = gfx::Rect(gfx::Point(base_x, base_y), size); - - int real_height = static_cast<int>(size.height() * visibility_percentage_); - int real_y = anchor_point_.y() - real_height; - - // Size this window to the bottom left corner starting at the anchor point. - if (real_height > 0) { - SetWindowPos(HWND_TOP, base_x, real_y, size.width(), real_height, 0); - container_view_->SchedulePaint(); - } else { - SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); - } -} - -void BlockedPopupContainer::CloseEachTabContents() { - while (!blocked_popups_.empty()) { - blocked_popups_.back().first->CloseContents(); - blocked_popups_.pop_back(); - } - - blocked_popups_.clear(); -} diff --git a/chrome/browser/views/blocked_popup_container.h b/chrome/browser/views/blocked_popup_container.h deleted file mode 100644 index de59a1e..0000000 --- a/chrome/browser/views/blocked_popup_container.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2008 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. - -#ifndef CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_H_ -#define CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_H_ - -#include <vector> - -#include "base/gfx/rect.h" -#include "chrome/browser/constrained_window.h" -#include "chrome/browser/tab_contents_delegate.h" -#include "chrome/common/animation.h" -#include "chrome/common/pref_member.h" -#include "chrome/views/container_win.h" - -class BlockedPopupContainerView; -class Profile; -class TabContents; -class TextButton; - -/////////////////////////////////////////////////////////////////////////////// -// -// BlockedPopupContainer -// -// This class takes ownership of TabContents that are unrequested popup -// windows and presents an interface to the user for launching them. (Or never -// showing them again) -// -class BlockedPopupContainer : public ConstrainedWindow, - public TabContentsDelegate, - public views::ContainerWin, - public Animation { - public: - virtual ~BlockedPopupContainer(); - - // Create a BlockedPopupContainer, anchoring the container to the lower right - // corner. - static BlockedPopupContainer* Create( - TabContents* owner, Profile* profile, const gfx::Point& initial_anchor); - - // Toggles the preference to display this notification. - void ToggleBlockedPopupNotification(); - - // Gets the current state of the show blocked popup notification preference. - bool GetShowBlockedPopupNotification(); - - // Adds a Tabbed contents to this container. |bounds| are the window bounds - // requested by the popup window. - void AddTabContents(TabContents* blocked_contents, const gfx::Rect& bounds); - - // Creates a window from blocked popup |index|. - void LaunchPopupIndex(int index); - - // Return the number of blocked popups - int GetTabContentsCount() const; - - // Returns the string to display to the user in the menu for item |index|. - std::wstring GetDisplayStringForItem(int index); - - // Deletes all popups and hides the interface parts. - void CloseAllPopups(); - - // Called to force this container to never show itself again. - void set_dismissed() { has_been_dismissed_ = true; } - - // Override from ConstrainedWindow: - virtual void CloseConstrainedWindow(); - virtual void RepositionConstrainedWindowTo(const gfx::Point& anchor_point); - virtual void WasHidden() { } - virtual void DidBecomeSelected() { } - virtual std::wstring GetWindowTitle() const; - virtual const gfx::Rect& GetCurrentBounds() const; - - // Override from TabContentsDelegate: - virtual void OpenURLFromTab(TabContents* source, - const GURL& url, const GURL& referrer, - WindowOpenDisposition disposition, - PageTransition::Type transition); - virtual void NavigationStateChanged(const TabContents* source, - unsigned changed_flags) { } - virtual void ReplaceContents(TabContents* source, - TabContents* new_contents); - virtual void AddNewContents(TabContents* source, - TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture); - virtual void ActivateContents(TabContents* contents) { } - virtual void LoadingStateChanged(TabContents* source) { } - virtual void CloseContents(TabContents* source); - virtual void MoveContents(TabContents* source, const gfx::Rect& pos); - virtual bool IsPopup(TabContents* source); - virtual TabContents* GetConstrainingContents(TabContents* source); - virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) { } - virtual void URLStarredChanged(TabContents* source, bool starred) { } - virtual void UpdateTargetURL(TabContents* source, const GURL& url) { } - - // Override from Animation: - virtual void AnimateToState(double state); - - protected: - // Override from views::ContainerWin: - virtual void OnFinalMessage(HWND window); - virtual void OnSize(UINT param, const CSize& size); - - private: - // Create a container for a certain TabContents. - BlockedPopupContainer(TabContents* owner, Profile* profile); - - // Initialize our Views and positions us to the lower right corner of the - // browser window. - void Init(const gfx::Point& initial_anchor); - - // Hides the UI portion of the container. - void HideSelf(); - - // Shows the UI portion of the container. - void ShowSelf(); - - // Sets our position, based on our |anchor_point_| and on our - // |visibility_percentage_|. This method is called whenever either of those - // change. - void SetPosition(); - - // Send a CloseContents() to each message in |blocked_popups_|. - void CloseEachTabContents(); - - // The TabContents that owns and constrains this BlockedPopupContainer. - TabContents* owner_; - - // TabContents. - std::vector<std::pair<TabContents*, gfx::Rect> > blocked_popups_; - - // Our associated view object. - BlockedPopupContainerView* container_view_; - - // Link to the show blocked popup preference. Used to both determine whether - // we should show ourself to the user... - BooleanPrefMember block_popup_pref_; - - // Once the container is hidden, this is set to prevent it from reappearing. - bool has_been_dismissed_; - - // True while animation in; false while animating out. - bool in_show_animation_; - - // Percentage of the window to show; used to animate in the notification. - double visibility_percentage_; - - // The bounds to report to the automation system (may not equal our actual - // bounds while animating in or out). - gfx::Rect bounds_; - - // The bottom right corner of where we should appear in our parent window. - gfx::Point anchor_point_; - - DISALLOW_COPY_AND_ASSIGN(BlockedPopupContainer); -}; - -#endif diff --git a/chrome/browser/views/browser_views.vcproj b/chrome/browser/views/browser_views.vcproj index 3463567..4a47e9a 100644 --- a/chrome/browser/views/browser_views.vcproj +++ b/chrome/browser/views/browser_views.vcproj @@ -462,14 +462,6 @@ > </File> <File - RelativePath=".\blocked_popup_container.cc" - > - </File> - <File - RelativePath=".\blocked_popup_container.h" - > - </File> - <File RelativePath=".\bookmark_bar_view.cc" > </File> @@ -534,6 +526,14 @@ > </File> <File + RelativePath=".\constrained_window_animation.cc" + > + </File> + <File + RelativePath=".\constrained_window_animation.h" + > + </File> + <File RelativePath=".\constrained_window_impl.cc" > </File> diff --git a/chrome/browser/views/constrained_window_animation.cc b/chrome/browser/views/constrained_window_animation.cc index e69de29..cedd0ba 100644 --- a/chrome/browser/views/constrained_window_animation.cc +++ b/chrome/browser/views/constrained_window_animation.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2006-2008 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/views/constrained_window_animation.h" +#include "chrome/browser/views/constrained_window_impl.h" + +// The duration of the animation. +static const int kDuration = 360; + +// The frame-rate for the animation. +static const int kFrameRate = 60; + +//////////////////////////////////////////////////////////////////////////////// +// ConstrainedWindowAnimation, public: + +ConstrainedWindowAnimation::ConstrainedWindowAnimation( + ConstrainedWindowImpl* window) + : Animation(kDuration, kFrameRate, NULL), window_(window) { +} + +ConstrainedWindowAnimation::~ConstrainedWindowAnimation() { +} + +//////////////////////////////////////////////////////////////////////////////// +// ConstrainedWindowAnimation, Animation implementation: + +void ConstrainedWindowAnimation::AnimateToState(double state) { + window_->SetTitlebarVisibilityPercentage(state); +} + diff --git a/chrome/browser/views/constrained_window_animation.h b/chrome/browser/views/constrained_window_animation.h index e69de29..8504155 100644 --- a/chrome/browser/views/constrained_window_animation.h +++ b/chrome/browser/views/constrained_window_animation.h @@ -0,0 +1,30 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_CONSTRAINED_WINDOW_ANIMATION_H__ +#define CHROME_BROWSER_VIEWS_CONSTRAINED_WINDOW_ANIMATION_H__ + +#include "chrome/common/animation.h" + +class ConstrainedWindowImpl; + +// Animates a titlebar of a suppressed constrained window up from the +// bottom of the screen. +class ConstrainedWindowAnimation : public Animation { + public: + explicit ConstrainedWindowAnimation(ConstrainedWindowImpl* window); + virtual ~ConstrainedWindowAnimation(); + + // Overridden from Animation: + virtual void AnimateToState(double state); + + private: + // The constrained window we're displaying. + ConstrainedWindowImpl* window_; + + DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowAnimation); +}; + +#endif // CHROME_BROWSER_VIEWS_CONSTRAINED_WINDOW_ANIMATION_H__ + diff --git a/chrome/browser/views/constrained_window_impl.cc b/chrome/browser/views/constrained_window_impl.cc index a1da56c..abd10fa 100644 --- a/chrome/browser/views/constrained_window_impl.cc +++ b/chrome/browser/views/constrained_window_impl.cc @@ -8,6 +8,8 @@ #include "chrome/app/chrome_dll_resource.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/tab_contents.h" +#include "chrome/browser/views/constrained_window_animation.h" +#include "chrome/browser/views/location_bar_view.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profile.h" #include "chrome/browser/toolbar_model.h" @@ -180,7 +182,8 @@ SkBitmap* OTRWindowResources::bitmaps_[]; class ConstrainedWindowNonClientView : public views::NonClientView, - public views::BaseButton::ButtonListener { + public views::BaseButton::ButtonListener, + public LocationBarView::Delegate { public: ConstrainedWindowNonClientView(ConstrainedWindowImpl* container, TabContents* owner); @@ -191,14 +194,20 @@ class ConstrainedWindowNonClientView // Calculates the pixel height of all pieces of a window that are // not part of the webcontent display area. + int CalculateNonClientHeight(bool with_url_field) const; gfx::Rect CalculateWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const; + const gfx::Rect& client_bounds, + bool with_url_field) const; void UpdateWindowTitle(); void set_window_delegate(views::WindowDelegate* window_delegate) { window_delegate_ = window_delegate; } + // Changes whether we display a throbber or the current favicon and + // forces a repaint of the titlebar. + void SetShowThrobber(bool show_throbber); + // Overridden from views::NonClientView: virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; virtual gfx::Size CalculateWindowSizeForClientSize(int width, @@ -218,11 +227,28 @@ class ConstrainedWindowNonClientView // Overridden from views::BaseButton::ButtonListener: virtual void ButtonPressed(views::BaseButton* sender); + // Overridden from LocationBarView::Delegate: + virtual TabContents* GetTabContents(); + virtual void OnInputInProgress(bool in_progress); + + // Updates the current throbber animation frame; called from the + // overloaded Run() and from SetShowThrobber(). + void UpdateThrobber(); + + // Whether we should display the throbber instead of the favicon. + bool should_show_throbber() const { + return show_throbber_ && current_throbber_frame_ != -1; + } + // Paints different parts of the window to the incoming canvas. void PaintFrameBorder(ChromeCanvas* canvas); void PaintTitleBar(ChromeCanvas* canvas); + void PaintThrobber(ChromeCanvas* canvas); void PaintWindowTitle(ChromeCanvas* canvas); + void UpdateLocationBar(); + bool ShouldDisplayURLField() const; + SkColor GetTitleColor() const { if (container_->owner()->profile()->IsOffTheRecord() || !win_util::ShouldUseVistaFrame()) { @@ -242,14 +268,58 @@ class ConstrainedWindowNonClientView views::Button* close_button_; + LocationBarView* location_bar_; + + // Specialization of ToolbarModel to obtain selected NavigationController for + // a constrained TabContents. + class ConstrainedWindowToolbarModel : public ToolbarModel { + public: + ConstrainedWindowToolbarModel(ConstrainedWindowImpl* constrained_window) + : constrained_window_(constrained_window) { + } + ~ConstrainedWindowToolbarModel() { } + + protected: + virtual NavigationController* GetNavigationController() { + TabContents* tab = constrained_window_->constrained_contents(); + return tab ? tab->controller() : NULL; + } + + private: + ConstrainedWindowImpl* constrained_window_; + + DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowToolbarModel); + }; + + // The model used for the states of the location bar. + ConstrainedWindowToolbarModel toolbar_model_; + + // Whether we should display the animated throbber instead of the + // favicon. + bool show_throbber_; + + // The timer used to update frames for the throbber. + base::RepeatingTimer<ConstrainedWindowNonClientView> throbber_timer_; + + // The current index into the throbber image strip. + int current_throbber_frame_; + static void InitClass(); + // The throbber to display while a constrained window is loading. + static SkBitmap throbber_frames_; + + // The number of animation frames in throbber_frames_. + static int throbber_frame_count_; + // The font to be used to render the titlebar text. static ChromeFont title_font_; DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowNonClientView); }; +SkBitmap ConstrainedWindowNonClientView::throbber_frames_; +int ConstrainedWindowNonClientView::throbber_frame_count_ = -1; ChromeFont ConstrainedWindowNonClientView::title_font_; static const int kWindowLeftSpacing = 5; static const int kWindowControlsTopOffset = 1; @@ -264,9 +334,16 @@ static const int kWindowHorizontalBorderSize = 5; static const int kWindowVerticalBorderSize = 5; static const int kWindowIconSize = 16; +// How much wider or shorter the location bar is relative to the client area. +static const int kLocationBarOffset = 2; +// Spacing between the location bar and the content area. +static const int kLocationBarSpacing = 1; + static const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0); static const SkColor kContentsBorderColor = SkColorSetRGB(219, 235, 255); +static const int kThrobberFrameTimeMs = 30; + //////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowNonClientView, public: @@ -275,7 +352,11 @@ ConstrainedWindowNonClientView::ConstrainedWindowNonClientView( : NonClientView(), container_(container), window_delegate_(NULL), - close_button_(new views::Button) { + close_button_(new views::Button), + location_bar_(NULL), + show_throbber_(false), + current_throbber_frame_(-1), + toolbar_model_(container) { InitClass(); if (owner->profile()->IsOffTheRecord()) { resources_.reset(new OTRWindowResources); @@ -297,11 +378,43 @@ ConstrainedWindowNonClientView::ConstrainedWindowNonClientView( views::Button::ALIGN_MIDDLE); close_button_->SetListener(this, 0); AddChildView(close_button_); + + // Note: we don't need for a controller because no input event will be ever + // processed from a constrained window. + location_bar_ = new LocationBarView(owner->profile(), + NULL, + &toolbar_model_, + this, + true); + AddChildView(location_bar_); } ConstrainedWindowNonClientView::~ConstrainedWindowNonClientView() { } +void ConstrainedWindowNonClientView::UpdateLocationBar() { + if (ShouldDisplayURLField()) { + std::wstring url_spec; + TabContents* tab = container_->constrained_contents(); + url_spec = gfx::ElideUrl(tab->GetURL(), + ChromeFont(), + 0, + tab->profile()->GetPrefs()->GetString(prefs::kAcceptLanguages)); + std::wstring ev_text, ev_tooltip_text; + tab->GetSSLEVText(&ev_text, &ev_tooltip_text), + location_bar_->Update(NULL); + } +} + +bool ConstrainedWindowNonClientView::ShouldDisplayURLField() const { + // If the dialog is not fully initialized, default to showing the URL field. + if (!container_ || !container_->owner() || !container_->owner()->delegate()) + return true; + + return !container_->is_dialog() && + container_->owner()->delegate()->ShouldDisplayURLField(); +} + int ConstrainedWindowNonClientView::CalculateTitlebarHeight() const { int height; if (window_delegate_ && window_delegate_->ShouldShowWindowTitle()) { @@ -313,9 +426,18 @@ int ConstrainedWindowNonClientView::CalculateTitlebarHeight() const { return height; } +int ConstrainedWindowNonClientView::CalculateNonClientHeight( + bool with_url_field) const { + int r = CalculateTitlebarHeight(); + if (with_url_field) + r += location_bar_->GetPreferredSize().height(); + return r; +} + gfx::Rect ConstrainedWindowNonClientView::CalculateWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const { - int non_client_height = CalculateTitlebarHeight(); + const gfx::Rect& client_bounds, + bool with_url_field) const { + int non_client_height = CalculateNonClientHeight(with_url_field); gfx::Rect window_bounds = client_bounds; window_bounds.set_width( window_bounds.width() + 2 * kWindowHorizontalBorderSize); @@ -329,6 +451,25 @@ gfx::Rect ConstrainedWindowNonClientView::CalculateWindowBoundsForClientBounds( void ConstrainedWindowNonClientView::UpdateWindowTitle() { SchedulePaint(title_bounds_, false); + UpdateLocationBar(); +} + +void ConstrainedWindowNonClientView::SetShowThrobber(bool show_throbber) { + show_throbber_ = show_throbber; + + if (show_throbber) { + if (!throbber_timer_.IsRunning()) + throbber_timer_.Start( + TimeDelta::FromMilliseconds(kThrobberFrameTimeMs), this, + &ConstrainedWindowNonClientView::UpdateThrobber); + } else { + if (throbber_timer_.IsRunning()) { + throbber_timer_.Stop(); + UpdateThrobber(); + } + } + + Layout(); } //////////////////////////////////////////////////////////////////////////////// @@ -337,7 +478,7 @@ void ConstrainedWindowNonClientView::UpdateWindowTitle() { gfx::Rect ConstrainedWindowNonClientView::CalculateClientAreaBounds( int width, int height) const { - int non_client_height = CalculateTitlebarHeight(); + int non_client_height = CalculateNonClientHeight(ShouldDisplayURLField()); return gfx::Rect(kWindowHorizontalBorderSize, non_client_height, std::max(0, width - (2 * kWindowHorizontalBorderSize)), std::max(0, height - non_client_height - kWindowVerticalBorderSize)); @@ -349,7 +490,8 @@ gfx::Size ConstrainedWindowNonClientView::CalculateWindowSizeForClientSize( // This is only used for truly constrained windows, which does not include // popups generated from a user gesture since those are detached immediately. gfx::Rect window_bounds = - CalculateWindowBoundsForClientBounds(gfx::Rect(0, 0, width, height)); + CalculateWindowBoundsForClientBounds(gfx::Rect(0, 0, width, height), + ShouldDisplayURLField()); return window_bounds.size(); } @@ -427,7 +569,18 @@ void ConstrainedWindowNonClientView::Paint(ChromeCanvas* canvas) { } void ConstrainedWindowNonClientView::Layout() { + bool should_display_url_field = false; + if (location_bar_) { + should_display_url_field = ShouldDisplayURLField(); + location_bar_->SetVisible(should_display_url_field); + } + + int location_bar_height = 0; gfx::Size ps; + if (should_display_url_field) { + ps = location_bar_->GetPreferredSize(); + location_bar_height = ps.height(); + } ps = close_button_->GetPreferredSize(); close_button_->SetBounds(width() - ps.width() - kWindowControlsRightOffset, @@ -435,6 +588,15 @@ void ConstrainedWindowNonClientView::Layout() { int titlebar_height = CalculateTitlebarHeight(); if (window_delegate_) { + if (show_throbber_) { + int icon_y = (titlebar_height - kWindowIconSize) / 2; + icon_bounds_.SetRect(kWindowLeftSpacing, icon_y, 0, 0); + icon_bounds_.set_width(kWindowIconSize); + icon_bounds_.set_height(kWindowIconSize); + } else { + icon_bounds_.SetRect(0, 0, 0, 0); + } + if (window_delegate_->ShouldShowWindowTitle()) { int spacing = kWindowLeftSpacing; int title_right = close_button_->x() - spacing; @@ -451,13 +613,21 @@ void ConstrainedWindowNonClientView::Layout() { } client_bounds_ = CalculateClientAreaBounds(width(), height()); + if (should_display_url_field) { + location_bar_->SetBounds(client_bounds_.x() - kLocationBarOffset, + client_bounds_.y() - location_bar_height - + kLocationBarSpacing, + client_bounds_.width() + kLocationBarOffset * 2, + location_bar_height); + location_bar_->Layout(); + } container_->client_view()->SetBounds(client_bounds_); } gfx::Size ConstrainedWindowNonClientView::GetPreferredSize() { gfx::Size prefsize = container_->client_view()->GetPreferredSize(); - prefsize.Enlarge(2 * kWindowHorizontalBorderSize, - CalculateTitlebarHeight() + + prefsize.Enlarge(2 * kWindowHorizontalBorderSize, + CalculateNonClientHeight(ShouldDisplayURLField()) + kWindowVerticalBorderSize); return prefsize; } @@ -470,6 +640,8 @@ void ConstrainedWindowNonClientView::ViewHierarchyChanged(bool is_add, // subsequently resized all the parent-child relationships are established. if (is_add && GetContainer() && child == this) AddChildView(container_->client_view()); + if (location_bar_ && !location_bar_->IsInitialized()) + location_bar_->Init(); } } @@ -483,8 +655,27 @@ void ConstrainedWindowNonClientView::ButtonPressed(views::BaseButton* sender) { } //////////////////////////////////////////////////////////////////////////////// +// ConstrainedWindowNonClientView, LocationBarView::Delegate +// implementation: +TabContents* ConstrainedWindowNonClientView::GetTabContents() { + return container_->owner(); +} + +void ConstrainedWindowNonClientView::OnInputInProgress(bool in_progress) { +} + +//////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowNonClientView, private: +void ConstrainedWindowNonClientView::UpdateThrobber() { + if (show_throbber_) + current_throbber_frame_ = ++current_throbber_frame_ % throbber_frame_count_; + else + current_throbber_frame_ = -1; + + SchedulePaint(); +} + void ConstrainedWindowNonClientView::PaintFrameBorder(ChromeCanvas* canvas) { SkBitmap* top_left_corner = resources_->GetPartBitmap(FRAME_TOP_LEFT_CORNER); SkBitmap* top_right_corner = @@ -547,11 +738,24 @@ void ConstrainedWindowNonClientView::PaintTitleBar(ChromeCanvas* canvas) { if (!window_delegate_) return; + if (should_show_throbber()) + PaintThrobber(canvas); + if (window_delegate_->ShouldShowWindowTitle()) { PaintWindowTitle(canvas); } } +void ConstrainedWindowNonClientView::PaintThrobber(ChromeCanvas* canvas) { + int image_size = throbber_frames_.height(); + int image_offset = current_throbber_frame_ * image_size; + canvas->DrawBitmapInt(throbber_frames_, + image_offset, 0, image_size, image_size, + icon_bounds_.x(), icon_bounds_.y(), + image_size, image_size, + false); +} + void ConstrainedWindowNonClientView::PaintWindowTitle(ChromeCanvas* canvas) { int title_x = MirroredLeftPointForRect(title_bounds_); canvas->DrawStringInt(container_->GetWindowTitle(), title_font_, @@ -563,6 +767,13 @@ void ConstrainedWindowNonClientView::PaintWindowTitle(ChromeCanvas* canvas) { void ConstrainedWindowNonClientView::InitClass() { static bool initialized = false; if (!initialized) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + + throbber_frames_ = *rb.GetBitmapNamed(IDR_THROBBER); + DCHECK(throbber_frames_.width() % throbber_frames_.height() == 0); + throbber_frame_count_ = + throbber_frames_.width() / throbber_frames_.height(); + title_font_ = win_util::GetWindowTitleFont(); initialized = true; @@ -570,6 +781,44 @@ void ConstrainedWindowNonClientView::InitClass() { } //////////////////////////////////////////////////////////////////////////////// +// ConstrainedTabContentsWindowDelegate + +class ConstrainedTabContentsWindowDelegate : public views::WindowDelegate { + public: + explicit ConstrainedTabContentsWindowDelegate(TabContents* contents) + : contents_(contents), + contents_view_(NULL) { + } + + void set_contents_view(views::View* contents_view) { + contents_view_ = contents_view; + } + + // views::WindowDelegate implementation: + virtual bool CanResize() const { + return true; + } + virtual std::wstring GetWindowTitle() const { + return contents_->GetTitle(); + } + virtual bool ShouldShowWindowIcon() const { + return false; + } + virtual SkBitmap GetWindowIcon() { + return contents_->GetFavIcon(); + } + virtual views::View* GetContentsView() { + return contents_view_; + } + + private: + TabContents* contents_; + views::View* contents_view_; + + DISALLOW_EVIL_CONSTRUCTORS(ConstrainedTabContentsWindowDelegate); +}; + +//////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowImpl, public: // The space (in pixels) between minimized pop-ups stacked horizontally and @@ -587,11 +836,15 @@ ConstrainedWindowNonClientView* ConstrainedWindowImpl::non_client_view() { return static_cast<ConstrainedWindowNonClientView*>(non_client_view_); } -void ConstrainedWindowImpl::UpdateWindowTitle() { - UpdateUI(TabContents::INVALIDATE_TITLE); -} - void ConstrainedWindowImpl::ActivateConstrainedWindow() { + if (CanDetach()) { + // Detachable pop-ups are torn out as soon as the window is activated. + Detach(); + return; + } + + StopSuppressedAnimationIfRunning(); + // Other pop-ups are simply moved to the front of the z-order. SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); @@ -608,8 +861,21 @@ void ConstrainedWindowImpl::ActivateConstrainedWindow() { // that case and replay them when the WebContents becomes selected. focus_manager->StoreFocusedView(); - // Give our window the focus so we get keyboard messages. - ::SetFocus(GetHWND()); + if (constrained_contents_) { + // We contain another window, let's assume it knows how to process the + // focus and let's focus it. + // TODO(jcampan): so far this case is the WebContents case. We need to + // better find whether the inner window should get focus. + ::SetFocus(constrained_contents_->GetContainerHWND()); + } else { + views::View* view_to_focus = NULL; + if (window_delegate()) + view_to_focus = window_delegate()->GetInitiallyFocusedView(); + if (view_to_focus) + view_to_focus->RequestFocus(); + else // Give our window the focus so we get keyboard messages. + ::SetFocus(GetHWND()); + } } } @@ -624,53 +890,369 @@ void ConstrainedWindowImpl::CloseConstrainedWindow() { Close(); } +void ConstrainedWindowImpl::RepositionConstrainedWindowTo( + const gfx::Point& anchor_point) { + anchor_point_ = anchor_point; + ResizeConstrainedTitlebar(); +} + +bool ConstrainedWindowImpl::IsSuppressedConstrainedWindow() const { + return !is_dialog_; +} + void ConstrainedWindowImpl::WasHidden() { - DLOG(INFO) << "WasHidden"; + if (constrained_contents_) + constrained_contents_->WasHidden(); } void ConstrainedWindowImpl::DidBecomeSelected() { - DLOG(INFO) << "DidBecomeSelected"; + if (constrained_contents_) + constrained_contents_->DidBecomeSelected(); } std::wstring ConstrainedWindowImpl::GetWindowTitle() const { - std::wstring display_title; + // TODO(erg): (http://b/1085485) Need to decide if we what we want long term + // in our popup window titles. + std::wstring page_title; if (window_delegate()) - display_title = window_delegate()->GetWindowTitle(); - else - display_title = L"Untitled"; + page_title = window_delegate()->GetWindowTitle(); + + std::wstring display_title; + bool title_set = false; + if (constrained_contents_) { + // TODO(erg): This is in the process of being translated now, but we need + // to do UI work so that display_title is "IDS_BLOCKED_POPUP - <page + // title>". + display_title = l10n_util::GetString(IDS_BLOCKED_POPUP); + title_set = true; + } + + if (!title_set) { + if (page_title.empty()) + display_title = L"Untitled"; + else + display_title = page_title; + } return display_title; } +void ConstrainedWindowImpl::UpdateWindowTitle() { + UpdateUI(TabContents::INVALIDATE_TITLE); +} + const gfx::Rect& ConstrainedWindowImpl::GetCurrentBounds() const { return current_bounds_; } //////////////////////////////////////////////////////////////////////////////// +// ConstrainedWindowImpl, TabContentsDelegate implementation: + +void ConstrainedWindowImpl::NavigationStateChanged( + const TabContents* source, + unsigned int changed_flags) { + UpdateUI(changed_flags); +} + +void ConstrainedWindowImpl::ReplaceContents(TabContents* source, + TabContents* new_contents) { + source->set_delegate(NULL); + + constrained_contents_ = new_contents; + constrained_contents_->set_delegate(this); + UpdateUI(TabContents::INVALIDATE_EVERYTHING); +} + +void ConstrainedWindowImpl::AddNewContents(TabContents* source, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + // Pass this to the delegate, since we can't open new tabs in the Constrained + // Window, they are sent up to the browser to open as new tabs. + owner_->AddNewContents( + this, new_contents, disposition, initial_pos, user_gesture); +} + +void ConstrainedWindowImpl::ActivateContents(TabContents* contents) { + // Ask the delegate's (which is a TabContents) own TabContentsDelegate to + // activate itself... + owner_->delegate()->ActivateContents(owner_); + + // Set as the foreground constrained window. + ActivateConstrainedWindow(); +} + +void ConstrainedWindowImpl::OpenURLFromTab(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) { + // We ignore source right now. + owner_->OpenURL(this, url, referrer, disposition, transition); +} + +void ConstrainedWindowImpl::LoadingStateChanged(TabContents* source) { + // TODO(beng): (http://b/1085543) Implement a throbber for the Constrained + // Window. + UpdateUI(TabContents::INVALIDATE_EVERYTHING); + non_client_view()->SetShowThrobber(source->is_loading()); +} + +void ConstrainedWindowImpl::NavigateToPage(TabContents* source, + const GURL& url, + PageTransition::Type transition) { + UpdateUI(TabContents::INVALIDATE_EVERYTHING); +} + +void ConstrainedWindowImpl::SetTitlebarVisibilityPercentage(double percentage) { + titlebar_visibility_ = percentage; + ResizeConstrainedTitlebar(); +} + +void ConstrainedWindowImpl::StartSuppressedAnimation() { + animation_.reset(new ConstrainedWindowAnimation(this)); + animation_->Start(); +} + +void ConstrainedWindowImpl::StopSuppressedAnimationIfRunning() { + if(animation_.get()) { + animation_->Stop(); + SetTitlebarVisibilityPercentage(1.0); + animation_.reset(); + } +} + +void ConstrainedWindowImpl::CloseContents(TabContents* source) { + Close(); +} + +void ConstrainedWindowImpl::MoveContents(TabContents* source, + const gfx::Rect& pos) { + if (!IsSuppressedConstrainedWindow()) + SetWindowBounds(pos); + else + ResizeConstrainedWindow(pos.width(), pos.height()); +} + +bool ConstrainedWindowImpl::IsPopup(TabContents* source) { + return true; +} + +TabContents* ConstrainedWindowImpl::GetConstrainingContents( + TabContents* source) { + return owner_; +} + +void ConstrainedWindowImpl::ToolbarSizeChanged(TabContents* source, + bool finished) { + // We don't control the layout of anything that could be animating, + // so do nothing. +} + +//////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowImpl, private: ConstrainedWindowImpl::ConstrainedWindowImpl( TabContents* owner, - views::WindowDelegate* window_delegate) + views::WindowDelegate* window_delegate, + TabContents* constrained_contents) + : CustomFrameWindow(window_delegate, + new ConstrainedWindowNonClientView(this, owner)), + contents_window_delegate_(window_delegate), + constrained_contents_(constrained_contents), + titlebar_visibility_(0.0) { + Init(owner); +} + +ConstrainedWindowImpl::ConstrainedWindowImpl( + TabContents* owner, + views::WindowDelegate* window_delegate) : CustomFrameWindow(window_delegate, - new ConstrainedWindowNonClientView(this, owner)) { + new ConstrainedWindowNonClientView(this, owner)), + constrained_contents_(NULL) { Init(owner); } void ConstrainedWindowImpl::Init(TabContents* owner) { owner_ = owner; focus_restoration_disabled_ = false; + is_dialog_ = false; + contents_container_ = NULL; set_window_style(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU); set_focus_on_creation(false); } +void ConstrainedWindowImpl::ResizeConstrainedTitlebar() { + DCHECK(constrained_contents_) + << "ResizeConstrainedTitlebar() is only valid for web popups"; + // If we represent a web popup and we were not opened as the result of a + // user gesture, we override the position specified in |initial_bounds| to + // place ourselves at the bottom right of the parent HWND. + CRect this_bounds; + GetClientRect(&this_bounds); + + ResizeConstrainedWindow(this_bounds.Width(), this_bounds.Height()); +} + +void ConstrainedWindowImpl::ResizeConstrainedWindow(int width, int height) { + DCHECK(constrained_contents_) + << "ResizeConstrainedTitlebar() is only valid for web popups"; + + // Make sure we aren't larger then our containing tab contents. + if (width > anchor_point_.x()) + width = anchor_point_.x(); + + // Determine the height of the title bar of a constrained window, so + // that we can offset by that much vertically if necessary... + int titlebar_height = non_client_view()->CalculateTitlebarHeight(); + + int visible_titlebar_pixels = + static_cast<int>(titlebar_height * titlebar_visibility_); + + int x = anchor_point_.x() - width; + int y = anchor_point_.y() - visible_titlebar_pixels; + + // NOTE: Previously, we passed in |visible_titlebar_pixels| instead + // of |height|. This didn't actually change any of the properties of + // the child HWNDS. If we ever set the |anchor_point_| intelligently + // so that it deals with scrollbars, we'll need to change height + // back to |visible_titlebar_pixels| and find a different solution, + // otherwise part of the window will be displayed over the scrollbar. + SetWindowPos(NULL, x, y, width, height, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW); +} + void ConstrainedWindowImpl::InitAsDialog(const gfx::Rect& initial_bounds) { + is_dialog_ = true; non_client_view()->set_window_delegate(window_delegate()); CustomFrameWindow::Init(owner_->GetContainerHWND(), initial_bounds); ActivateConstrainedWindow(); } +void ConstrainedWindowImpl::InitWindowForContents( + TabContents* constrained_contents, + ConstrainedTabContentsWindowDelegate* delegate) { + constrained_contents_ = constrained_contents; + constrained_contents_->set_delegate(this); + contents_container_ = new views::HWNDView; + delegate->set_contents_view(contents_container_); + non_client_view()->set_window_delegate(contents_window_delegate_.get()); +} + +void ConstrainedWindowImpl::InitSizeForContents( + const gfx::Rect& initial_bounds) { + CustomFrameWindow::Init(owner_->GetContainerHWND(), initial_bounds); + contents_container_->Attach(constrained_contents_->GetContainerHWND()); + + // TODO(brettw) this should be done some other way, see + // WebContentsView::SizeContents. + if (constrained_contents_->AsWebContents()) { + // This should always be true, all constrained windows are WebContents. + constrained_contents_->AsWebContents()->view()->SizeContents( + gfx::Size(contents_container_->width(), + contents_container_->height())); + } else { + NOTREACHED(); + } + current_bounds_ = initial_bounds; + + // Note that this is HWND_TOP, not HWND_TOPMOST... this is important + // because otherwise the window will not be visible on top of the + // RenderWidgetHostView! + win_util::SetChildBounds(GetHWND(), GetParent(), HWND_TOP, initial_bounds, + kConstrainedWindowEdgePadding, 0); +} + +bool ConstrainedWindowImpl::CanDetach() const { + // Constrained TabContentses can be detached, dialog boxes can't. + return constrained_contents_ ? true : false; +} + +void ConstrainedWindowImpl::Detach() { + DCHECK(CanDetach()); + + StopSuppressedAnimationIfRunning(); + + // Tell the container not to restore focus to whatever view was focused last, + // since this will interfere with the new window activation in the case where + // a constrained window is destroyed by being detached. + focus_restoration_disabled_ = true; + + // Detach the HWND immediately. + contents_container_->Detach(); + contents_container_ = NULL; + + // To try and create as seamless as possible a popup experience, web pop-ups + // are automatically detached when the user interacts with them. We can + // dial this back if we feel this is too much. + + // The detached contents "should" be re-parented by the delegate's + // DetachContents, but we clear the delegate pointing to us just in case. + constrained_contents_->set_delegate(NULL); + + // We want to detach the constrained window at the same position on screen + // as the constrained window, so we need to get its screen bounds. + CRect constrained_window_bounds; + GetBounds(&constrained_window_bounds, true); + + // Obtain the constrained TabContents' size from its HWND... + CRect bounds; + ::GetWindowRect(constrained_contents_->GetContainerHWND(), &bounds); + + // This block of code was added by Ben, and is simply false in any world with + // magic_browzr turned off. Eventually, the if block here should go away once + // we get rid of the old pre-magic_browzr window implementation, but for now + // (and at least the next beta release), it's here to stay and magic_browzr + // is off by default. + if (g_browser_process->IsUsingNewFrames()) { + // ... but overwrite its screen position with the screen position of its + // containing ConstrainedWindowImpl. We do this because the code called by + // |DetachContents| assumes the bounds contains position and size + // information similar to what is sent when a popup is not suppressed and + // must be opened, i.e. the position is the screen position of the top left + // of the detached popup window, and the size is the size of the content + // area. + bounds.SetRect(constrained_window_bounds.left, + constrained_window_bounds.top, + constrained_window_bounds.left + bounds.Width(), + constrained_window_bounds.top + bounds.Height()); + } + + // Save the cursor position so that we know where to send a mouse message + // when the new detached window is created. + CPoint cursor_pos; + ::GetCursorPos(&cursor_pos); + gfx::Point screen_point(cursor_pos.x, cursor_pos.y); + + // Determine what aspect of the constrained frame was clicked on, so that we + // can continue the mouse move on this aspect of the detached frame. + int frame_component = static_cast<int>(OnNCHitTest(screen_point.ToPOINT())); + + // Finally we actually detach the TabContents, and then clean up. + owner_->DetachContents(this, constrained_contents_, gfx::Rect(bounds), + screen_point, frame_component); + constrained_contents_ = NULL; + Close(); +} + +void ConstrainedWindowImpl::SetWindowBounds(const gfx::Rect& bounds) { + // Note: SetChildBounds ensures that the constrained window is constrained + // to the bounds of its parent, however there remains a bug where the + // window is positioned incorrectly when the outer window is opened on + // a monitor that has negative coords (e.g. secondary monitor to left + // of primary, see http://b/issue?id=967905.) + gfx::Size window_size = non_client_view()->CalculateWindowSizeForClientSize( + bounds.width(), bounds.height()); + + current_bounds_ = bounds; + current_bounds_.set_width(window_size.width()); + current_bounds_.set_height(window_size.height()); + win_util::SetChildBounds(GetHWND(), GetParent(), NULL, current_bounds_, + kConstrainedWindowEdgePadding, 0); +} + void ConstrainedWindowImpl::UpdateUI(unsigned int changed_flags) { if (changed_flags & TabContents::INVALIDATE_TITLE) non_client_view()->UpdateWindowTitle(); @@ -700,6 +1282,20 @@ void ConstrainedWindowImpl::OnDestroy() { focus_manager->RestoreFocusedView(); } + // If we have a child TabContents, we need to unhook it here so that it is + // not automatically WM_DESTROYed by virtue of the fact that it is part of + // our Window hierarchy. Rather, it needs to be destroyed just like top level + // TabContentses are: from OnMsgCloseACK in RenderWidgetHost. So we hide the + // TabContents and sever the parent relationship now. Note the GetParent + // check so that we don't hide and re-parent TabContentses that have been + // detached and re-attached into a new top level browser window via a user + // drag action. + if (constrained_contents_ && + ::GetParent(constrained_contents_->GetContainerHWND()) == GetHWND()) { + ::ShowWindow(constrained_contents_->GetContainerHWND(), SW_HIDE); + ::SetParent(constrained_contents_->GetContainerHWND(), NULL); + } + // Make sure we call super so that it can do its cleanup. Window::OnDestroy(); } @@ -708,6 +1304,10 @@ void ConstrainedWindowImpl::OnFinalMessage(HWND window) { // Tell our constraining TabContents that we've gone so it can update its // list. owner_->WillClose(this); + if (constrained_contents_) { + constrained_contents_->CloseContents(); + constrained_contents_ = NULL; + } ContainerWin::OnFinalMessage(window); } @@ -727,15 +1327,28 @@ void ConstrainedWindowImpl::OnGetMinMaxInfo(LPMINMAXINFO mm_info) { LRESULT ConstrainedWindowImpl::OnMouseActivate(HWND window, UINT hittest_code, UINT message) { + // We need to store this value before we call ActivateConstrainedWindow() + // since the window may be detached and so this function will return false + // afterwards. + bool can_detach = CanDetach(); + // We only detach the window if the user clicked on the title bar. That // way, users can click inside the contents of legitimate popups obtained // with a mouse gesture. if (hittest_code != HTCLIENT && hittest_code != HTNOWHERE && hittest_code != HTCLOSE) { ActivateConstrainedWindow(); + } else { + // If the user did not click on the title bar, don't stop message + // propagation. + can_detach = false; } - return MA_ACTIVATE; + // If the popup can be detached, then we tell the parent window not to + // activate since we will already have adjusted activation ourselves. We also + // do _not_ eat the event otherwise the user will have to click again to + // interact with the popup. + return can_detach ? MA_NOACTIVATEANDEAT : MA_ACTIVATE; } void ConstrainedWindowImpl::OnWindowPosChanged(WINDOWPOS* window_pos) { @@ -759,3 +1372,27 @@ ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog( window->InitAsDialog(initial_bounds); return window; } + +// static +ConstrainedWindow* ConstrainedWindow::CreateConstrainedPopup( + TabContents* parent, + const gfx::Rect& initial_bounds, + TabContents* constrained_contents) { + ConstrainedTabContentsWindowDelegate* d = + new ConstrainedTabContentsWindowDelegate(constrained_contents); + ConstrainedWindowImpl* window = + new ConstrainedWindowImpl(parent, d, constrained_contents); + window->InitWindowForContents(constrained_contents, d); + + gfx::Rect window_bounds = window->non_client_view()-> + CalculateWindowBoundsForClientBounds( + initial_bounds, + parent->delegate()->ShouldDisplayURLField()); + + window->InitSizeForContents(window_bounds); + + // This is a constrained popup window and thus we need to animate it in. + window->StartSuppressedAnimation(); + + return window; +} diff --git a/chrome/browser/views/constrained_window_impl.h b/chrome/browser/views/constrained_window_impl.h index f9371fe..479b173 100644 --- a/chrome/browser/views/constrained_window_impl.h +++ b/chrome/browser/views/constrained_window_impl.h @@ -25,31 +25,77 @@ class WindowDelegate; // a child HWND with a custom window frame. // class ConstrainedWindowImpl : public ConstrainedWindow, - public views::CustomFrameWindow { + public views::CustomFrameWindow, + public TabContentsDelegate { public: virtual ~ConstrainedWindowImpl(); // Returns the TabContents that constrains this Constrained Window. TabContents* owner() const { return owner_; } + TabContents* constrained_contents() const { return constrained_contents_; } // Returns the non-client view inside this Constrained Window. // NOTE: Defining the function body here would require pulling in the // declarations of ConstrainedWindowNonClientView, as well as all the classes // it depends on, from the .cc file; the benefit isn't worth it. ConstrainedWindowNonClientView* non_client_view(); - // Overridden from views::CustomFrameWindow: - virtual void UpdateWindowTitle(); - // Overridden from ConstrainedWindow: virtual void CloseConstrainedWindow(); virtual void ActivateConstrainedWindow(); - virtual void RepositionConstrainedWindowTo(const gfx::Point& anchor_point) {} + virtual void RepositionConstrainedWindowTo(const gfx::Point& anchor_point); + virtual bool IsSuppressedConstrainedWindow() const; virtual void WasHidden(); virtual void DidBecomeSelected(); virtual std::wstring GetWindowTitle() const; + virtual void UpdateWindowTitle(); virtual const gfx::Rect& GetCurrentBounds() const; + // Overridden from PageNavigator (TabContentsDelegate's base interface): + virtual void OpenURLFromTab(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition); + + // Overridden from TabContentsDelegate: + virtual void NavigationStateChanged(const TabContents* source, + unsigned changed_flags); + virtual void ReplaceContents(TabContents* source, + TabContents* new_contents); + virtual void AddNewContents(TabContents* source, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture); + virtual void ActivateContents(TabContents* contents); + virtual void LoadingStateChanged(TabContents* source); + virtual void CloseContents(TabContents* source); + virtual void MoveContents(TabContents* source, const gfx::Rect& pos); + virtual bool IsPopup(TabContents* source); + virtual TabContents* GetConstrainingContents(TabContents* source); + virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); + virtual void URLStarredChanged(TabContents* source, bool) {} + virtual void UpdateTargetURL(TabContents* source, const GURL& url) {} + virtual bool CanBlur() const { return false; } + + virtual void NavigateToPage(TabContents* source, const GURL& url, + PageTransition::Type transition); + + + bool is_dialog() { return is_dialog_; } + + // Changes the visibility of the titlebar. |percentage| is a real + // number ranged 0,1. + void SetTitlebarVisibilityPercentage(double percentage); + + // Starts a ConstrainedWindowAnimation to slide in the titlebar of + // this suppressed constrained popup window. + void StartSuppressedAnimation(); + + // Stops the ConstrainedWindowAnimation, making the entire titlebar visible. + void StopSuppressedAnimationIfRunning(); + protected: // Windows message handlers: virtual void OnDestroy(); @@ -64,23 +110,78 @@ class ConstrainedWindowImpl : public ConstrainedWindow, // Use the static factory methods on ConstrainedWindow to construct a // ConstrainedWindow. ConstrainedWindowImpl(TabContents* owner, + views::WindowDelegate* window_delegate, + TabContents* constrained_contents); + ConstrainedWindowImpl(TabContents* owner, views::WindowDelegate* window_delegate); void Init(TabContents* owner); + // Called after changing either the anchor point or titlebar + // visibility of a suppressed popup. + // + // @see RepositionConstrainedWindowTo + // @see SetTitlebarVisibilityPercentage + void ResizeConstrainedTitlebar(); + + // Called to change the size of a constrained window. Moves the + // window to the anchor point (taking titlebar visibility into + // account) and sets the pop up size. + void ResizeConstrainedWindow(int width, int height); + // Initialize the Constrained Window as a Constrained Dialog containing a // views::View client area. void InitAsDialog(const gfx::Rect& initial_bounds); + // Builds the underlying HWND and window delegates for a newly + // created popup window. + // + // We have to split the initialization process for a popup window in + // two because we first need to initialize a proper window delegate + // so that when we query for desired size, we get accurate data. If + // we didn't do this, windows will initialize to being smaller then + // the desired content size plus room for browser chrome. + void InitWindowForContents(TabContents* constrained_contents, + ConstrainedTabContentsWindowDelegate* delegate); + + // Sets the initial bounds for a newly created popup window. + // + // This is the second part of the initialization process started + // with InitWindowForContents. For the parameter initial_bounds to + // have been calculated correctly, InitWindowForContents must have + // been run first. + void InitSizeForContents(const gfx::Rect& initial_bounds); + + // Returns true if the Constrained Window can be detached from its owner. + bool CanDetach() const; + + // Detach the Constrained TabContents from its owner. + void Detach(); + // Updates the portions of the UI as specified in |changed_flags|. void UpdateUI(unsigned int changed_flags); + // Place and size the window, constraining to the bounds of the |owner_|. + void SetWindowBounds(const gfx::Rect& bounds); + // The TabContents that owns and constrains this ConstrainedWindow. TabContents* owner_; + // The TabContents constrained by |owner_|. + TabContents* constrained_contents_; + // True if focus should not be restored to whatever view was focused last // when this window is destroyed. bool focus_restoration_disabled_; + // A default views::WindowDelegate implementation for this window when + // a TabContents is being constrained. (For the Constrained Dialog case, the + // caller is required to provide the WindowDelegate). + scoped_ptr<views::WindowDelegate> contents_window_delegate_; + + // We keep a reference on the HWNDView so we can properly detach the tab + // contents when detaching. + views::HWNDView* contents_container_; + // true if this window is really a constrained dialog. This is set by // InitAsDialog(). bool is_dialog_; @@ -89,6 +190,14 @@ class ConstrainedWindowImpl : public ConstrainedWindow, // the constrained title bar. gfx::Point anchor_point_; + // The 0,1 percentage representing what amount of a titlebar of a + // suppressed popup window should be visible. Used to animate those + // titlebars in. + double titlebar_visibility_; + + // The animation class which animates constrained windows onto the page. + scoped_ptr<ConstrainedWindowAnimation> animation_; + // Current display rectangle (relative to owner_'s visible area). gfx::Rect current_bounds_; diff --git a/chrome/browser/views/constrained_window_impl_interactive_uitest.cc b/chrome/browser/views/constrained_window_impl_interactive_uitest.cc index 5f672a3..860a009 100644 --- a/chrome/browser/views/constrained_window_impl_interactive_uitest.cc +++ b/chrome/browser/views/constrained_window_impl_interactive_uitest.cc @@ -92,9 +92,61 @@ TEST_F(InteractiveConstrainedWindowTest, TestOpenAndResizeTo) { ASSERT_LT(rect.height(), 200); } +TEST_F(InteractiveConstrainedWindowTest, ClickingXClosesConstrained) { + // Clicking X on a constrained window should close the window instead of + // unconstrain it. + scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); + ASSERT_TRUE(browser.get()); + + scoped_ptr<WindowProxy> window( + automation()->GetWindowForBrowser(browser.get())); + ASSERT_TRUE(window.get()); + + scoped_ptr<TabProxy> tab(browser->GetTab(0)); + ASSERT_TRUE(tab.get()); + + std::wstring filename(test_data_directory_); + file_util::AppendToPath(&filename, L"constrained_files"); + file_util::AppendToPath(&filename, + L"constrained_window.html"); + ASSERT_TRUE(tab->NavigateToURL(net::FilePathToFileURL(filename))); + + // Wait for the animation to finish. + Sleep(1000); + + // Calculate the center of the "X" + gfx::Rect tab_view_bounds; + ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, + &tab_view_bounds, true)); + gfx::Point constrained_close_button; + constrained_close_button.set_x( + tab_view_bounds.x() + tab_view_bounds.width() - kRightCloseButtonOffset); + constrained_close_button.set_y( + tab_view_bounds.y() + tab_view_bounds.height() - + kBottomCloseButtonOffset); + + // Click that X. + POINT click_point(constrained_close_button.ToPOINT()); + ASSERT_TRUE(window->SimulateOSClick(click_point, + views::Event::EF_LEFT_BUTTON_DOWN)); + + // Check that there is only one constrained window. (There would have been + // two pre-click). + int constrained_window_count; + EXPECT_TRUE(tab->WaitForChildWindowCountToChange( + 2, &constrained_window_count, 5000)); + EXPECT_EQ(constrained_window_count, 1); + + // Check that there is still only one window (so we know we didn't activate + // the constrained popup.) + int browser_window_count; + EXPECT_TRUE(automation()->GetBrowserWindowCount(&browser_window_count)); + EXPECT_EQ(browser_window_count, 1); +} + // Tests that in the window.open() equivalent of a fork bomb, we stop building // windows. -TEST_F(InteractiveConstrainedWindowTest, DISABLED_DontSpawnEndlessPopups) { +TEST_F(InteractiveConstrainedWindowTest, DontSpawnEndlessPopups) { scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser.get()); diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 36ea812..cc415ec 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -113,6 +113,12 @@ void BrowserView::ShowTabContents(TabContents* contents) { frame_->ShowTabContents(contents); } +void BrowserView::ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_pt, + int frame_component) { + frame_->ContinueDetachConstrainedWindowDrag(mouse_pt, frame_component); +} + void BrowserView::SizeToContents(const gfx::Rect& contents_bounds) { frame_->SizeToContents(contents_bounds); } @@ -225,3 +231,4 @@ void BrowserView::ViewHierarchyChanged(bool is_add, initialized_ = true; } } + diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index a83d08a..5d81317 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -48,6 +48,9 @@ class BrowserView : public BrowserWindow, virtual void Activate(); virtual void FlashFrame(); virtual void ShowTabContents(TabContents* contents); + virtual void ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_pt, + int frame_component); virtual void SizeToContents(const gfx::Rect& contents_bounds); virtual void SetAcceleratorTable( std::map<views::Accelerator, int>* accelerator_table); @@ -102,3 +105,4 @@ class BrowserView : public BrowserWindow, }; #endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_H_ + diff --git a/chrome/browser/views/frame/browser_view2.cc b/chrome/browser/views/frame/browser_view2.cc index 7081665..477a910 100644 --- a/chrome/browser/views/frame/browser_view2.cc +++ b/chrome/browser/views/frame/browser_view2.cc @@ -351,6 +351,40 @@ void BrowserView2::FlashFrame() { FlashWindowEx(&fwi); } +void BrowserView2::ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_point, + int frame_component) { + HWND vc_hwnd = GetContainer()->GetHWND(); + if (frame_component == HTCLIENT) { + // If the user's mouse was over the content area of the popup when they + // clicked down, we need to re-play the mouse down event so as to actually + // send the click to the renderer. If we don't do this, the user needs to + // click again once the window is detached to interact. + HWND inner_hwnd = browser_->GetSelectedTabContents()->GetContentHWND(); + POINT window_point = mouse_point.ToPOINT(); + MapWindowPoints(HWND_DESKTOP, inner_hwnd, &window_point, 1); + PostMessage(inner_hwnd, WM_LBUTTONDOWN, MK_LBUTTON, + MAKELPARAM(window_point.x, window_point.y)); + } else if (frame_component != HTNOWHERE) { + // The user's mouse is already moving, and the left button is down, but we + // need to start moving this frame, so we _post_ it a NCLBUTTONDOWN message + // with the corresponding frame component as supplied by the constrained + // window where the user clicked. This tricks Windows into believing the + // user just started performing that operation on the newly created window. + // All the frame moving and sizing is then handled automatically by + // Windows. We use PostMessage because we need to return to the message + // loop first for Windows' built in moving/sizing to be triggered. + POINTS pts; + pts.x = mouse_point.x(); + pts.y = mouse_point.y(); + PostMessage(vc_hwnd, WM_NCLBUTTONDOWN, frame_component, + reinterpret_cast<LPARAM>(&pts)); + // Also make sure the right cursor for the action is set. + PostMessage(vc_hwnd, WM_SETCURSOR, reinterpret_cast<WPARAM>(vc_hwnd), + frame_component); + } +} + void BrowserView2::SizeToContents(const gfx::Rect& contents_bounds) { frame_->SizeToContents(contents_bounds); } @@ -1158,3 +1192,4 @@ void BrowserView2::InitClass() { initialized = true; } } + diff --git a/chrome/browser/views/frame/browser_view2.h b/chrome/browser/views/frame/browser_view2.h index 1399f65..a2d65f7 100644 --- a/chrome/browser/views/frame/browser_view2.h +++ b/chrome/browser/views/frame/browser_view2.h @@ -141,6 +141,9 @@ class BrowserView2 : public BrowserWindow, virtual void UpdateTitleBar(); virtual void Activate(); virtual void FlashFrame(); + virtual void ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_point, + int frame_component); virtual void SizeToContents(const gfx::Rect& contents_bounds); virtual void SetAcceleratorTable( std::map<views::Accelerator, int>* accelerator_table); @@ -368,3 +371,4 @@ class BrowserView2 : public BrowserWindow, }; #endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW2_H_ + diff --git a/chrome/browser/views/old_frames/vista_frame.cc b/chrome/browser/views/old_frames/vista_frame.cc index 5dad752..0bc1714 100644 --- a/chrome/browser/views/old_frames/vista_frame.cc +++ b/chrome/browser/views/old_frames/vista_frame.cc @@ -1516,6 +1516,28 @@ TabStrip* VistaFrame::GetTabStrip() const { return tabstrip_; } +void VistaFrame::ContinueDetachConstrainedWindowDrag(const gfx::Point& mouse_pt, + int frame_component) { + // Need to force a paint at this point so that the newly created window looks + // correct. (Otherwise parts of the tabstrip are clipped). + CRect cr; + GetClientRect(&cr); + PaintNow(gfx::Rect(cr)); + + // The user's mouse is already moving, and the left button is down, but we + // need to start moving this frame, so we _post_ it a NCLBUTTONDOWN message + // with the HTCAPTION flag to trick windows into believing the user just + // started dragging on the title bar. All the frame moving is then handled + // automatically by windows. Note that we use PostMessage here since we need + // to return to the message loop first otherwise Windows' built in move code + // will not be able to be triggered. + POINTS pts; + pts.x = mouse_pt.x(); + pts.y = mouse_pt.y(); + PostMessage(WM_NCLBUTTONDOWN, frame_component, + reinterpret_cast<LPARAM>(&pts)); +} + void VistaFrame::SizeToContents(const gfx::Rect& contents_bounds) { // First we need to ensure everything has an initial size. Currently, the // window has the wrong size, but that's OK, doing this will allow us to diff --git a/chrome/browser/views/old_frames/vista_frame.h b/chrome/browser/views/old_frames/vista_frame.h index a6aa6ad..ff5de5c 100644 --- a/chrome/browser/views/old_frames/vista_frame.h +++ b/chrome/browser/views/old_frames/vista_frame.h @@ -165,6 +165,9 @@ class VistaFrame : public BrowserWindow, virtual void* GetPlatformID(); virtual void ShowTabContents(TabContents* contents); virtual TabStrip* GetTabStrip() const; + virtual void ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_pt, + int frame_component); virtual void SizeToContents(const gfx::Rect& contents_bounds); virtual void SetAcceleratorTable( std::map<views::Accelerator, int>* accelerator_table); @@ -408,3 +411,4 @@ class VistaFrame : public BrowserWindow, DISALLOW_EVIL_CONSTRUCTORS(VistaFrame); }; #endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_VISTA_FRAME_H__ + diff --git a/chrome/browser/views/old_frames/xp_frame.cc b/chrome/browser/views/old_frames/xp_frame.cc index 5ebf22a..ca365b2 100644 --- a/chrome/browser/views/old_frames/xp_frame.cc +++ b/chrome/browser/views/old_frames/xp_frame.cc @@ -2385,6 +2385,35 @@ gfx::Rect XPFrame::GetNormalBounds() { return gfx::Rect(wp.rcNormalPosition); } +void XPFrame::ContinueDetachConstrainedWindowDrag(const gfx::Point& mouse_pt, + int frame_component) { + // Need to force a paint at this point so that the newly created window looks + // correct. (Otherwise parts of the tabstrip are clipped). + CRect cr; + GetClientRect(&cr); + PaintNow(gfx::Rect(cr)); + + // The user's mouse is already moving, and the left button is down, but we + // need to start moving this frame, so we _post_ it a NCLBUTTONDOWN message + // with the HTCAPTION flag to trick windows into believing the user just + // started dragging on the title bar. All the frame moving is then handled + // automatically by windows. Note that we use PostMessage here since we need + // to return to the message loop first otherwise Windows' built in move code + // will not be able to be triggered. + POINTS pts; + pts.x = mouse_pt.x(); + pts.y = mouse_pt.y(); + if (frame_component == HTCAPTION) { + // XPFrame uses windows' standard move code, so this works. + PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, reinterpret_cast<LPARAM>(&pts)); + } else { + // Because xpframe does its own resizing, and does not respond properly to + // WM_NCHITTEST, there's no reliable way for us to handle other frame + // component types. Alas. This will be corrected when XPFrame subclasses + // views::CustomFrameWindow, some day. + } +} + void XPFrame::SizeToContents(const gfx::Rect& contents_bounds) { // First we need to ensure everything has an initial size. Currently, the // window has the wrong size, but that's OK, doing this will allow us to @@ -2472,4 +2501,4 @@ void XPFrame::ShelfVisibilityChangedImpl(TabContents* current_tab) { // tab switches). if (needs_layout_ && current_tab) Layout(); -} +}
\ No newline at end of file diff --git a/chrome/browser/views/old_frames/xp_frame.h b/chrome/browser/views/old_frames/xp_frame.h index 2f1fe5a..c73b47d 100644 --- a/chrome/browser/views/old_frames/xp_frame.h +++ b/chrome/browser/views/old_frames/xp_frame.h @@ -176,6 +176,8 @@ class XPFrame : public BrowserWindow, virtual void ShowTabContents(TabContents* contents); virtual TabStrip* GetTabStrip() const; + virtual void ContinueDetachConstrainedWindowDrag(const gfx::Point& mouse_pt, + int frame_component); void SizeToContents(const gfx::Rect& contents_bounds); // Returns true if the frame should be rendered in an active state. @@ -523,3 +525,4 @@ class XPFrame : public BrowserWindow, }; #endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_XP_FRAME_H__ + diff --git a/chrome/views/menu_button.cc b/chrome/views/menu_button.cc index c0c3e2e..e9205b1 100644 --- a/chrome/views/menu_button.cc +++ b/chrome/views/menu_button.cc @@ -54,7 +54,7 @@ MenuButton::MenuButton(const std::wstring& text, show_menu_marker_(show_menu_marker) { if (kMenuMarker == NULL) { kMenuMarker = ResourceBundle::GetSharedInstance() - .GetBitmapNamed(IDR_MENU_DROPARROW); + .GetBitmapNamed(IDR_MENU_MARKER); } SetTextAlignment(TextButton::ALIGN_LEFT); } @@ -257,3 +257,4 @@ void MenuButton::OnMouseExited(const MouseEvent& event) { } } // namespace views + |