diff options
-rw-r--r-- | chrome/browser/browser.cc | 12 | ||||
-rw-r--r-- | chrome/browser/browser.h | 3 | ||||
-rw-r--r-- | chrome/browser/browser.scons | 1 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/dock_info.cc | 481 | ||||
-rw-r--r-- | chrome/browser/dock_info.h | 136 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.cc | 6 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.h | 10 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_controller.cc | 499 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_controller.h | 20 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_view.cc | 6 | ||||
-rw-r--r-- | chrome/common/slide_animation.h | 7 | ||||
-rw-r--r-- | chrome/common/win_util.cc | 4 |
14 files changed, 1085 insertions, 112 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 49333b6..375f566 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -22,6 +22,7 @@ #include "chrome/browser/cert_store.h" #include "chrome/browser/character_encoding.h" #include "chrome/browser/debugger/debugger_window.h" +#include "chrome/browser/dock_info.h" #include "chrome/browser/dom_ui/new_tab_ui.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/history_tab_ui.h" @@ -1196,12 +1197,19 @@ GURL Browser::GetBlankTabURL() const { } void Browser::CreateNewStripWithContents(TabContents* detached_contents, - const gfx::Rect& window_bounds) { + const gfx::Rect& window_bounds, + const DockInfo& dock_info) { DCHECK(type_ == TYPE_NORMAL); + gfx::Rect new_window_bounds = window_bounds; + bool maximize = false; + if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize)) + dock_info.AdjustOtherWindowBounds(); + // Create an empty new browser window the same size as the old one. Browser* browser = new Browser(TYPE_NORMAL, profile_); - browser->set_override_bounds(window_bounds); + browser->set_override_bounds(new_window_bounds); + browser->set_override_maximized(maximize); browser->CreateBrowserWindow(); browser->tabstrip_model()->AppendTabContents(detached_contents, true); browser->window()->Show(); diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 4a77152..bb88bc5 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -301,7 +301,8 @@ class Browser : public TabStripModelDelegate, // Overridden from TabStripModelDelegate: virtual GURL GetBlankTabURL() const; virtual void CreateNewStripWithContents(TabContents* detached_contents, - const gfx::Rect& window_bounds); + const gfx::Rect& window_bounds, + const DockInfo& dock_info); virtual int GetDragActions() const; // Construct a TabContents for a given URL, profile and transition type. // If instance is not null, its process will be used to render the tab. diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index 202945f..a4213e3 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -153,6 +153,7 @@ if env['PLATFORM'] == 'win32': 'chrome_plugin_browsing_context.cc', 'chrome_plugin_host.cc', 'controller.cc', + 'dock_info.cc', 'dom_ui/chrome_url_data_manager.cc', 'dom_ui/dom_ui_host.cc', 'dom_ui/html_dialog_contents.cc', diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index 3a791a3..f900e92 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -998,6 +998,14 @@ > </File> <File + RelativePath=".\dock_info.cc" + > + </File> + <File + RelativePath=".\dock_info.h" + > + </File> + <File RelativePath=".\find_notification_details.h" > </File> diff --git a/chrome/browser/dock_info.cc b/chrome/browser/dock_info.cc new file mode 100644 index 0000000..fdf9f57 --- /dev/null +++ b/chrome/browser/dock_info.cc @@ -0,0 +1,481 @@ +// 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/dock_info.h" + +#include "base/basictypes.h" +#include "base/logging.h" +#include "chrome/browser/views/frame/browser_view.h" + +namespace { + +// Distance in pixels between the hotspot and when the hint should be shown. +const int kHotSpotDeltaX = 100; +const int kHotSpotDeltaY = 80; + +// Distance in pixels between the hotspot and when the hint should be shown +// and enabled. +const int kEnableDeltaX = 50; +const int kEnableDeltaY = 37; + +// Distance used when maximizing. The maximize area is the whole top of the +// monitor. +const int kMaximizeHotSpotDeltaY = 100; +const int kMaximizeEnableDeltaY = 50; + +// Returns true if |screen_loc| is close to the hotspot at |x|, |y|. If the +// point is close enough to the hotspot true is returned and |in_enable_area| +// is set appropriately. +bool IsCloseToPoint(const gfx::Point& screen_loc, + int x, + int y, + bool* in_enable_area) { + int delta_x = abs(x - screen_loc.x()); + int delta_y = abs(y - screen_loc.y()); + *in_enable_area = (delta_x < kEnableDeltaX && delta_y < kEnableDeltaY); + return *in_enable_area || (delta_x < kHotSpotDeltaX && + delta_y < kHotSpotDeltaY); +} + +// Variant of IsCloseToPoint used for monitor relative positions. +bool IsCloseToMonitorPoint(const gfx::Point& screen_loc, + int x, + int y, + DockInfo::Type type, + bool* in_enable_area) { + // Because the monitor relative positions are aligned with the edge of the + // monitor these need to be handled differently. + int delta_x = abs(x - screen_loc.x()); + int delta_y = abs(y - screen_loc.y()); + + int enable_delta_x = kEnableDeltaX; + int enable_delta_y = kEnableDeltaY; + int hot_spot_delta_x = kHotSpotDeltaX; + int hot_spot_delta_y = kHotSpotDeltaY; + + switch (type) { + case DockInfo::LEFT_HALF: + case DockInfo::RIGHT_HALF: + enable_delta_x += enable_delta_x; + hot_spot_delta_x += hot_spot_delta_x; + break; + + + case DockInfo::MAXIMIZE: + case DockInfo::BOTTOM_HALF: + enable_delta_y += enable_delta_y; + hot_spot_delta_y += hot_spot_delta_y; + break; + + default: + NOTREACHED(); + return false; + } + *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y); + bool result = (*in_enable_area || (delta_x < hot_spot_delta_x && + delta_y < hot_spot_delta_y)); + if (type != DockInfo::MAXIMIZE) + return result; + + // Make the maximize area the whole top of the monitor. + int max_delta_y = abs(screen_loc.y() - y); + *in_enable_area = (*in_enable_area || (max_delta_y < kMaximizeEnableDeltaY)); + return *in_enable_area || (max_delta_y < kMaximizeHotSpotDeltaY); +} + +// BaseWindowFinder ----------------------------------------------------------- + +// Base class used to locate a window. This is intended to be used with the +// various win32 functions that iterate over windows. +// +// A subclass need only override ShouldStopIterating to determine when +// iteration should stop. +class BaseWindowFinder { + public: + // Creates a BaseWindowFinder with the specified set of HWNDs to ignore. + BaseWindowFinder(const std::set<HWND>& ignore) : ignore_(ignore) {} + virtual ~BaseWindowFinder() {} + + protected: + // Returns true if iteration should stop, false if iteration should continue. + virtual bool ShouldStopIterating(HWND window) = 0; + + static BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) { + BaseWindowFinder* finder = reinterpret_cast<BaseWindowFinder*>(lParam); + if (finder->ignore_.find(hwnd) != finder->ignore_.end()) + return TRUE; + + return finder->ShouldStopIterating(hwnd) ? FALSE : TRUE; + } + + private: + const std::set<HWND>& ignore_; + + DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder); +}; + +// TopMostFinder -------------------------------------------------------------- + +// Helper class to determine if a particular point of a window is not obscured +// by another window. +class TopMostFinder : public BaseWindowFinder { + public: + // Returns true if |window| is the topmost window at the location + // |screen_loc|, not including the windows in |ignore|. + static bool IsTopMostWindowAtPoint(HWND window, + const gfx::Point& screen_loc, + const std::set<HWND>& ignore) { + TopMostFinder finder(window, screen_loc, ignore); + return finder.is_top_most_; + } + + virtual bool ShouldStopIterating(HWND hwnd) { + if (hwnd == target_) { + // Window is topmost, stop iterating. + is_top_most_ = true; + return true; + } + + if (::IsWindowVisible(hwnd)) { + CRect r; + if (::GetWindowRect(hwnd, &r) && r.PtInRect(screen_loc_.ToPOINT())) { + // Not the topmost, stop iterating. + return true; + } + } + return false; + } + + private: + TopMostFinder(HWND window, + const gfx::Point& screen_loc, + const std::set<HWND>& ignore) + : BaseWindowFinder(ignore), + target_(window), + screen_loc_(screen_loc), + is_top_most_(false) { + EnumWindows(WindowCallbackProc, reinterpret_cast<LPARAM>(this)); + } + + // The window we're looking for. + HWND target_; + + // Location of window to find. + gfx::Point screen_loc_; + + // Is target_ the top most window? This is initially false but set to true + // in ShouldStopIterating if target_ is passed in. + bool is_top_most_; + + DISALLOW_COPY_AND_ASSIGN(TopMostFinder); +}; + +// WindowFinder --------------------------------------------------------------- + +// Helper class to determine if a particular point contains a window from our +// process. +class LocalProcessWindowFinder : public BaseWindowFinder { + public: + // Returns the hwnd from our process at screen_loc that is not obscured by + // another window. Returns NULL otherwise. + static HWND GetProcessWindowAtPoint(const gfx::Point& screen_loc, + const std::set<HWND>& ignore) { + LocalProcessWindowFinder finder(screen_loc, ignore); + if (finder.result_ && + TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc, + ignore)) { + return finder.result_; + } + return NULL; + } + + protected: + virtual bool ShouldStopIterating(HWND hwnd) { + CRect r; + if (::IsWindowVisible(hwnd) && ::GetWindowRect(hwnd, &r) && + r.PtInRect(screen_loc_.ToPOINT())) { + result_ = hwnd; + return true; + } + return false; + } + + private: + LocalProcessWindowFinder(const gfx::Point& screen_loc, + const std::set<HWND>& ignore) + : BaseWindowFinder(ignore), + screen_loc_(screen_loc), + result_(NULL) { + EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, + reinterpret_cast<LPARAM>(this)); + } + + // Position of the mouse. + gfx::Point screen_loc_; + + // The resulting window. This is initially null but set to true in + // ShouldStopIterating if an appropriate window is found. + HWND result_; + + DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder); +}; + +// DockToWindowFinder --------------------------------------------------------- + +// Helper class for creating a DockInfo from a specified point. +class DockToWindowFinder : public BaseWindowFinder { + public: + // Returns the DockInfo for the specified point. If there is no docking + // position for the specified point the returned DockInfo has a type of NONE. + static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_loc, + const std::set<HWND>& ignore) { + DockToWindowFinder finder(screen_loc, ignore); + if (!finder.result_.hwnd() || + !TopMostFinder::IsTopMostWindowAtPoint(finder.result_.hwnd(), + finder.result_.hot_spot(), + ignore)) { + return DockInfo(); + } + return finder.result_; + } + + protected: + virtual bool ShouldStopIterating(HWND hwnd) { + BrowserWindow* window = BrowserView::GetBrowserWindowForHWND(hwnd); + CRect bounds; + if (!window || !::IsWindowVisible(hwnd) || + !::GetWindowRect(hwnd, &bounds)) { + return false; + } + + // Check the three corners we allow docking to. We don't currently allow + // docking to top of window as it conflicts with docking to the tab strip. + if (CheckPoint(hwnd, bounds.left, (bounds.top + bounds.bottom) / 2, + DockInfo::LEFT_OF_WINDOW) || + CheckPoint(hwnd, bounds.right - 1, (bounds.top + bounds.bottom) / 2, + DockInfo::RIGHT_OF_WINDOW) || + CheckPoint(hwnd, (bounds.left + bounds.right) / 2, bounds.bottom - 1, + DockInfo::BOTTOM_OF_WINDOW)) { + return true; + } + return false; + } + + private: + DockToWindowFinder(const gfx::Point& screen_loc, + const std::set<HWND>& ignore) + : BaseWindowFinder(ignore), + screen_loc_(screen_loc) { + EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, + reinterpret_cast<LPARAM>(this)); + } + + bool CheckPoint(HWND hwnd, int x, int y, DockInfo::Type type) { + bool in_enable_area; + if (IsCloseToPoint(screen_loc_, x, y, &in_enable_area)) { + result_.set_in_enable_area(in_enable_area); + result_.set_hwnd(hwnd); + result_.set_type(type); + result_.set_hot_spot(gfx::Point(x, y)); + return true; + } + return false; + } + + // The location to look for. + gfx::Point screen_loc_; + + // The resulting DockInfo. + DockInfo result_; + + DISALLOW_COPY_AND_ASSIGN(DockToWindowFinder); +}; + +} // namespace + +// DockInfo ------------------------------------------------------------------- + +DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point, + const std::set<HWND>& ignore) { + // Try docking to a window first. + DockInfo info = DockToWindowFinder::GetDockInfoAtPoint(screen_point, ignore); + + HMONITOR monitor = MonitorFromPoint(screen_point.ToPOINT(), + MONITOR_DEFAULTTONULL); + MONITORINFO monitor_info = {0}; + monitor_info.cbSize = sizeof(MONITORINFO); + if (!monitor || !GetMonitorInfo(monitor, &monitor_info)) { + info.type_ = NONE; + return info; + } + info.monitor_bounds_ = gfx::Rect(monitor_info.rcWork); + + if (info.type() != DockInfo::NONE) + return info; + + // No window relative positions. Try monitor relative positions. + RECT& m_bounds = monitor_info.rcWork; + int mid_x = (m_bounds.left + m_bounds.right) / 2; + int mid_y = (m_bounds.top + m_bounds.bottom) / 2; + + bool result = + info.CheckMonitorPoint(screen_point, mid_x, m_bounds.top, + DockInfo::MAXIMIZE) || + info.CheckMonitorPoint(screen_point, mid_x, m_bounds.bottom, + DockInfo::BOTTOM_HALF) || + info.CheckMonitorPoint(screen_point, m_bounds.left, mid_y, + DockInfo::LEFT_HALF) || + info.CheckMonitorPoint(screen_point, m_bounds.right, mid_y, + DockInfo::RIGHT_HALF); + + return info; +} + +HWND DockInfo::GetLocalProcessWindowAtPoint(const gfx::Point& screen_point, + const std::set<HWND>& ignore) { + return + LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore); +} + +bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) { + if (type_ == NONE) + return false; + + if (hwnd_) { + return IsCloseToPoint(screen_point, hot_spot_.x(), hot_spot_.y(), + &in_enable_area_); + } + + return monitor_bounds_.Contains(screen_point) && + IsCloseToMonitorPoint(screen_point, hot_spot_.x(), + hot_spot_.y(), type_, &in_enable_area_); +} + +bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds, + bool* maximize_new_window) const { + if (type_ == NONE || !in_enable_area_) + return false; + + RECT window_rect; + if (hwnd_ && !GetWindowRect(hwnd_, &window_rect)) + return false; + + int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2; + int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2; + bool unmaximize_other_window = false; + + *maximize_new_window = false; + + switch (type_) { + case LEFT_OF_WINDOW: + new_window_bounds->SetRect(monitor_bounds_.x(), window_rect.top, + half_m_width, window_rect.bottom - window_rect.top); + break; + + case RIGHT_OF_WINDOW: + new_window_bounds->SetRect(monitor_bounds_.x() + half_m_width, + window_rect.top, half_m_width, window_rect.bottom - window_rect.top); + break; + + case TOP_OF_WINDOW: + new_window_bounds->SetRect(window_rect.left, monitor_bounds_.y(), + window_rect.right - window_rect.left, + half_m_height); + break; + + case BOTTOM_OF_WINDOW: + new_window_bounds->SetRect(window_rect.left, + monitor_bounds_.y() + half_m_height, + window_rect.right - window_rect.left, + half_m_height); + break; + + case LEFT_HALF: + new_window_bounds->SetRect(monitor_bounds_.x(), monitor_bounds_.y(), + half_m_width, monitor_bounds_.height()); + break; + + case RIGHT_HALF: + new_window_bounds->SetRect(monitor_bounds_.right() - half_m_width, + monitor_bounds_.y(), half_m_width, monitor_bounds_.height()); + break; + + case BOTTOM_HALF: + new_window_bounds->SetRect(monitor_bounds_.x(), + monitor_bounds_.y() + half_m_height, + monitor_bounds_.width(), half_m_height); + break; + + case MAXIMIZE: + *maximize_new_window = true; + break; + + default: + NOTREACHED(); + } + return true; +} + +void DockInfo::AdjustOtherWindowBounds() const { + if (!in_enable_area_) + return; + + RECT window_rect; + if (!hwnd_ || !GetWindowRect(hwnd_, &window_rect)) + return; + + gfx::Rect other_window_bounds; + int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2; + int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2; + + switch (type_) { + case LEFT_OF_WINDOW: + other_window_bounds.SetRect(monitor_bounds_.x() + half_m_width, + window_rect.top, half_m_width, window_rect.bottom - window_rect.top); + break; + + case RIGHT_OF_WINDOW: + other_window_bounds.SetRect(monitor_bounds_.x(), window_rect.top, + half_m_width, window_rect.bottom - window_rect.top); + break; + + case TOP_OF_WINDOW: + other_window_bounds.SetRect(window_rect.left, + monitor_bounds_.y() + half_m_height, + window_rect.right - window_rect.left, + half_m_height); + break; + + case BOTTOM_OF_WINDOW: + other_window_bounds.SetRect(window_rect.left, monitor_bounds_.y(), + window_rect.right - window_rect.left, + half_m_height); + break; + + default: + return; + } + + if (IsZoomed(hwnd_)) { + // We're docking relative to another window, we need to make sure the + // window we're docking to isn't maximized. + ShowWindow(hwnd_, SW_RESTORE | SW_SHOWNA); + } + ::SetWindowPos(hwnd_, HWND_TOP, other_window_bounds.x(), + other_window_bounds.y(), other_window_bounds.width(), + other_window_bounds.height(), + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); +} + +bool DockInfo::CheckMonitorPoint(const gfx::Point& screen_loc, + int x, + int y, + Type type) { + if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_)) { + hot_spot_.SetPoint(x, y); + type_ = type; + return true; + } + return false; +} diff --git a/chrome/browser/dock_info.h b/chrome/browser/dock_info.h new file mode 100644 index 0000000..819322e --- /dev/null +++ b/chrome/browser/dock_info.h @@ -0,0 +1,136 @@ +// 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_DOCK_INFO_H_ +#define CHROME_BROWSER_DOCK_INFO_H_ + +#include <set> +#include <windows.h> + +#include "base/gfx/point.h" +#include "base/gfx/rect.h" + +class Profile; + +// DockInfo is used to do determine possible dock locations for a dragged +// tab. To use DockInfo invoke GetDockInfoAtPoint. This returns a new +// DockInfo whose type indicates the type of dock that should occur based +// on the screen location. As the user drags the mouse around invoke +// IsValidForPoint, this returns true if the DockInfo is still valid for the +// new location. If the DockInfo is not valid, invoke GetDockInfoAtPoint to +// get the new DockInfo. Use GetNewWindowBounds to get the position to place +// the new window at. +// +// DockInfos are cheap and explicitly allow copy and assignment operators. +class DockInfo { + public: + // Possible dock positions. + enum Type { + // Indicates there is no valid dock position for the current location. + NONE, + + // Indicates the new window should be positioned relative to the window + // identified by hwnd(). + LEFT_OF_WINDOW, + RIGHT_OF_WINDOW, + BOTTOM_OF_WINDOW, + TOP_OF_WINDOW, + + // Indicates the window should be maximized on the monitor at hot_spot. + MAXIMIZE, + + // Indicates the window should be docked to a specific side of the monitor. + LEFT_HALF, + RIGHT_HALF, + BOTTOM_HALF + }; + + DockInfo() : type_(NONE), hwnd_(NULL), in_enable_area_(false) {} + + // Returns the DockInfo for the specified point |screen_point|. |ignore| + // contains the set of hwnds to ignore from consideration. This contains the + // dragged window as well as any windows showing possible dock locations. + // + // If there is no docking position for the specified location the returned + // DockInfo has a type of NONE. + static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point, + const std::set<HWND>& ignore); + + // Returns the top most window from the current process at |screen_point|. + // See GetDockInfoAtPoint for a description of |ignore|. This returns NULL if + // there is no window from the current process at |screen_point|, or another + // window obscures the topmost window from our process at |screen_point|. + static HWND GetLocalProcessWindowAtPoint(const gfx::Point& screen_point, + const std::set<HWND>& ignore); + + // Returns true if this DockInfo is valid for the specified point. This + // resets in_enable_area based on the new location. + bool IsValidForPoint(const gfx::Point& screen_point); + + // Returns the bounds for the new window in |new_window_bounds|. If the new + // window is to be maximized, |maximize_new_window| is set to true. + // This returns true if type is other than NONE or the mouse isn't in the + // enable area, false otherwise. + bool GetNewWindowBounds(gfx::Rect* new_window_bounds, + bool* maximize_new_window) const; + + // Adjust the bounds of the other window during docking. Does nothing if type + // is NONE, in_enable_are is false, or the type is not window relative. + void AdjustOtherWindowBounds() const; + + // Type of docking to occur. + void set_type(Type type) { type_ = type; } + Type type() const { return type_; } + + // The window to dock too. Is null for dock types that are relative to the + // monitor. + void set_hwnd(HWND hwnd) { hwnd_ = hwnd; } + HWND hwnd() const { return hwnd_; } + + // The location of the hotspot. + void set_hot_spot(const gfx::Point& hot_spot) { hot_spot_ = hot_spot; } + const gfx::Point& hot_spot() const { return hot_spot_; } + + // Bounds of the monitor. + void set_monitor_bounds(const gfx::Rect& monitor_bounds) { + monitor_bounds_ = monitor_bounds; + } + const gfx::Rect& monitor_bounds() const { return monitor_bounds_; } + + // Returns true if the drop should result in docking. DockInfo maintains two + // states (as indicated by this boolean): + // 1. The mouse is close enough to the hot spot such that a visual indicator + // should be shown, but if the user releases the mouse docking shouldn't + // result. This corresponds to a value of false for in_enable_area. + // 2. The mouse is close enough to the hot spot such that releasing the mouse + // should result in docking. This corresponds to a value of true for + // in_enable_area. + void set_in_enable_area(bool in_enable_area) { + in_enable_area_ = in_enable_area; + } + bool in_enable_area() const { return in_enable_area_; } + + // Returns true if |other| is considered equal to this. Two DockInfos are + // considered equal if they have the same type and same hwnd. + bool equals(const DockInfo& other) const { + return type_ == other.type_ && hwnd_ == other.hwnd_; + } + + // If screen_loc is close enough to the hot spot given by |x| and |y|, the + // type and hot_spot are set from the supplied parameters. This is used + // internally, there is no need to invoke this otherwise. + bool CheckMonitorPoint(const gfx::Point& screen_loc, + int x, + int y, + Type type); + + private: + Type type_; + HWND hwnd_; + gfx::Point hot_spot_; + gfx::Rect monitor_bounds_; + bool in_enable_area_; +}; + +#endif // CHROME_BROWSER_DOCK_INFO_H_ diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc index 176bf94..21ba9b5 100644 --- a/chrome/browser/tabs/tab_strip_model.cc +++ b/chrome/browser/tabs/tab_strip_model.cc @@ -401,9 +401,11 @@ void TabStripModel::SelectLastTab() { } void TabStripModel::TearOffTabContents(TabContents* detached_contents, - const gfx::Rect& window_bounds) { + const gfx::Rect& window_bounds, + const DockInfo& dock_info) { DCHECK(detached_contents); - delegate_->CreateNewStripWithContents(detached_contents, window_bounds); + delegate_->CreateNewStripWithContents(detached_contents, window_bounds, + dock_info); } // Context menu functions. diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h index 386599c..d5d56f2 100644 --- a/chrome/browser/tabs/tab_strip_model.h +++ b/chrome/browser/tabs/tab_strip_model.h @@ -18,6 +18,7 @@ namespace gfx { class Point; } +class DockInfo; class GURL; class NavigationController; class Profile; @@ -94,8 +95,11 @@ class TabStripModelDelegate { // Ask for a new TabStripModel to be created and the given tab contents to // be added to it. Its size and position are reflected in |window_bounds|. + // If |dock_info|'s type is other than NONE, the newly created window should + // be docked as identified by |dock_info|. virtual void CreateNewStripWithContents(TabContents* contents, - const gfx::Rect& window_bounds) = 0; + const gfx::Rect& window_bounds, + const DockInfo& dock_info) = 0; enum { TAB_MOVE_ACTION = 1, @@ -351,7 +355,8 @@ class TabStripModel : public NotificationObserver { // The specified contents should be opened in a new tabstrip. void TearOffTabContents(TabContents* detached_contents, - const gfx::Rect& window_bounds); + const gfx::Rect& window_bounds, + const DockInfo& dock_info); // Context menu functions. enum ContextMenuCommand { @@ -517,4 +522,3 @@ class TabStripModel : public NotificationObserver { }; #endif // CHROME_BROWSER_TABS_TAB_STRIP_MODEL_H__ - diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc index 24c9b3c..071975f 100644 --- a/chrome/browser/tabs/tab_strip_model_unittest.cc +++ b/chrome/browser/tabs/tab_strip_model_unittest.cc @@ -4,6 +4,7 @@ #include "base/file_util.h" #include "base/path_service.h" +#include "chrome/browser/dock_info.h" #include "chrome/browser/dom_ui/new_tab_ui.h" #include "chrome/browser/navigation_controller.h" #include "chrome/browser/navigation_entry.h" @@ -994,7 +995,8 @@ class TabStripDummyDelegate : public TabStripModelDelegate { // Overridden from TabStripModelDelegate: virtual GURL GetBlankTabURL() const { return NewTabUIURL(); } virtual void CreateNewStripWithContents(TabContents* contents, - const gfx::Rect& window_bounds) {} + const gfx::Rect& window_bounds, + const DockInfo& dock_info) {} virtual int GetDragActions() const { return 0; } virtual TabContents* CreateTabContentsForURL( const GURL& url, diff --git a/chrome/browser/views/tabs/dragged_tab_controller.cc b/chrome/browser/views/tabs/dragged_tab_controller.cc index f81fc84..c88920a 100644 --- a/chrome/browser/views/tabs/dragged_tab_controller.cc +++ b/chrome/browser/views/tabs/dragged_tab_controller.cc @@ -3,17 +3,20 @@ // found in the LICENSE file. #include <math.h> +#include <set> #include "chrome/browser/views/tabs/dragged_tab_controller.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/tab_contents.h" +#include "chrome/browser/user_metrics.h" #include "chrome/browser/views/frame/browser_view.h" #include "chrome/browser/views/tabs/dragged_tab_view.h" #include "chrome/browser/views/tabs/hwnd_photobooth.h" #include "chrome/browser/views/tabs/tab.h" #include "chrome/browser/views/tabs/tab_strip.h" #include "chrome/browser/web_contents.h" +#include "chrome/common/animation.h" #include "chrome/views/event.h" #include "chrome/views/root_view.h" #include "skia/include/SkBitmap.h" @@ -22,95 +25,138 @@ static const int kHorizontalMoveThreshold = 16; // pixels namespace { -/////////////////////////////////////////////////////////////////////////////// -// WindowFinder -// A helper class that finds the topmost window from our thread under a -// particular point. This returns NULL if we don't have a window at the -// specified point, or there is another window from another app on top of our -// window at the specified point. -// -class WindowFinder { - public: - static HWND WindowForPoint(const gfx::Point& screen_point, HWND ignore1) { - WindowFinder instance(screen_point, ignore1); - return instance.GetResult(); - } +// Horizontal width of DockView. The height is 3/4 of this. If you change this, +// be sure and update the constants in DockInfo (kEnableDeltaX/kEnableDeltaY). +const int kDropWindowSize = 100; - private: - WindowFinder(const gfx::Point& screen_point, HWND ignore1) - : screen_point_(screen_point.ToPOINT()), - ignore1_(ignore1), - result1_(NULL), - result2_(NULL) { - } - - static BOOL CALLBACK EnumThreadWindowsProc(HWND hwnd, LPARAM lParam) { - WindowFinder* wf = reinterpret_cast<WindowFinder*>(lParam); - if (hwnd == wf->ignore1_) - return TRUE; - - if (::IsWindowVisible(hwnd)) { - CRect r; - ::GetWindowRect(hwnd, &r); - if (r.PtInRect(wf->screen_point_)) { - // We always deal with the root HWND. - wf->result1_ = GetAncestor(hwnd, GA_ROOT); - return FALSE; - } - } - return TRUE; +// TODO (glen): nuke this class in favor of something pretty. Consider this +// class a placeholder for the real thing. +class DockView : public views::View { + public: + explicit DockView(DockInfo::Type type) + : size_(kDropWindowSize), + rect_radius_(4), + stroke_size_(4), + inner_stroke_size_(2), + inner_margin_(8), + inner_padding_(8), + type_(type) {} + + virtual gfx::Size GetPreferredSize() { + return gfx::Size(size_, size_); } - static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { - WindowFinder* wf = reinterpret_cast<WindowFinder*>(lParam); - if (hwnd == wf->ignore1_) - return TRUE; - - if (hwnd == wf->result1_) { - // Result from first pass is the topmost window under point. Use it. - wf->result2_ = hwnd; - return FALSE; + virtual void PaintBackground(ChromeCanvas* canvas) { + int h = size_ * 3 / 4; + int outer_x = (width() - size_) / 2; + int outer_y = (height() - h) / 2; + switch (type_) { + case DockInfo::MAXIMIZE: + outer_y = 0; + break; + case DockInfo::LEFT_HALF: + outer_x = 0; + break; + case DockInfo::RIGHT_HALF: + outer_x = width() - size_; + break; + case DockInfo::BOTTOM_HALF: + outer_y = height() - h; + break; + default: + break; } - if (::IsWindowVisible(hwnd)) { - CRect r; - if (::GetWindowRect(hwnd, &r) && r.PtInRect(wf->screen_point_)) { - // Result from first pass is not the topmost window under point. - return FALSE; - } - } - return TRUE; // Keep iterating. - } - - HWND GetResult() { - // We take a two step approach to find the topmost window under point. - // Step 1: find the topmost window in our thread under point. - EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsProc, - reinterpret_cast<LPARAM>(this)); - if (result1_) { - // Step 2. - // We have a window under the point in our thread. Make sure there isn't - // another window from another app on top of our window at point. - // NOTE: EnumWindows iterates window from topmost window to bottommost - // window. - EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(this)); + SkRect outer_rect = { SkIntToScalar(outer_x), + SkIntToScalar(outer_y), + SkIntToScalar(outer_x + size_), + SkIntToScalar(outer_y + h) }; + + // Fill the background rect. + SkPaint paint; + paint.setColor(SkColorSetRGB(58, 58, 58)); + paint.setStyle(SkPaint::kFill_Style); + canvas->drawRoundRect(outer_rect, SkIntToScalar(rect_radius_), + SkIntToScalar(rect_radius_), paint); + + // Outline the background rect. + paint.setFlags(SkPaint::kAntiAlias_Flag); + paint.setStrokeWidth(SkIntToScalar(stroke_size_)); + paint.setColor(SK_ColorBLACK); + paint.setStyle(SkPaint::kStroke_Style); + canvas->drawRoundRect(outer_rect, SkIntToScalar(rect_radius_), + SkIntToScalar(rect_radius_), paint); + + // Then the inner rect. + int inner_x = outer_x + inner_margin_; + int inner_y = outer_y + inner_margin_; + int inner_width = + (size_ - inner_margin_ - inner_margin_ - inner_padding_) / 2; + int inner_height = (h - inner_margin_ - inner_margin_); + switch (type_) { + case DockInfo::LEFT_OF_WINDOW: + case DockInfo::RIGHT_OF_WINDOW: + DrawWindow(canvas, inner_x, inner_y, inner_width, inner_height); + DrawWindow(canvas, inner_x + inner_width + inner_padding_, inner_y, + inner_width, inner_height); + break; + + case DockInfo::TOP_OF_WINDOW: + case DockInfo::BOTTOM_OF_WINDOW: + inner_height = + (h - inner_margin_ - inner_margin_ - inner_padding_) / 2; + inner_width += inner_width + inner_padding_; + DrawWindow(canvas, inner_x, inner_y, inner_width, inner_height); + DrawWindow(canvas, inner_x, inner_y + inner_height + inner_padding_, + inner_width, inner_height); + break; + + case DockInfo::MAXIMIZE: + inner_width += inner_width + inner_padding_; + DrawWindow(canvas, inner_x, inner_y, inner_width, inner_height); + break; + + case DockInfo::LEFT_HALF: + DrawWindow(canvas, inner_x, inner_y, inner_width, inner_height); + break; + + case DockInfo::RIGHT_HALF: + DrawWindow(canvas, inner_x + inner_width + inner_padding_, inner_y, + inner_width, inner_height); + break; + + case DockInfo::BOTTOM_HALF: + inner_height = + (h - inner_margin_ - inner_margin_ - inner_padding_) / 2; + inner_width += inner_width + inner_padding_; + DrawWindow(canvas, inner_x, inner_y + inner_height + inner_padding_, + inner_width, inner_height); + break; } - return result2_; } - // Location we're looking for. - POINT screen_point_; - - // HWND to ignore. - HWND ignore1_; - - // Result from first pass. See docs in GetResult for details. - HWND result1_; + private: + void DrawWindow(ChromeCanvas* canvas, int x, int y, int w, int h) { + canvas->FillRectInt(SkColorSetRGB(160, 160, 160), x, y, w, h); + + SkPaint paint; + paint.setStrokeWidth(SkIntToScalar(inner_stroke_size_)); + paint.setColor(SK_ColorWHITE); + paint.setStyle(SkPaint::kStroke_Style); + SkRect rect = { SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w), + SkIntToScalar(y + h) }; + canvas->drawRect(rect, paint); + } - // Result from second pass. See docs in GetResult for details. - HWND result2_; + int size_; + int rect_radius_; + int stroke_size_; + int inner_stroke_size_; + int inner_margin_; + int inner_padding_; + DockInfo::Type type_; - DISALLOW_EVIL_CONSTRUCTORS(WindowFinder); + DISALLOW_COPY_AND_ASSIGN(DockView); }; gfx::Point ConvertScreenPointToTabStripPoint(TabStrip* tabstrip, @@ -121,7 +167,139 @@ gfx::Point ConvertScreenPointToTabStripPoint(TabStrip* tabstrip, screen_point.y() - tabstrip_topleft.y()); } -} +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// DockDisplayer + +// DockDisplayer is responsible for giving the user a visual indication of a +// possible dock position (as represented by DockInfo). DockDisplayer shows +// a window with a DockView in it. Two animations are used that correspond to +// the state of DockInfo::in_enable_area. +class DraggedTabController::DockDisplayer : public AnimationDelegate { + public: + DockDisplayer(DraggedTabController* controller, + const DockInfo& info) + : controller_(controller), + popup_(NULL), + popup_hwnd_(NULL), +#pragma warning(suppress: 4355) // Okay to pass "this" here. + hot_animation_(this), + enable_animation_(this), + hidden_(false), + in_enable_area_(info.in_enable_area()) { + gfx::Rect bounds(info.hot_spot().x() - kDropWindowSize / 2, + info.hot_spot().y() - kDropWindowSize / 2, + kDropWindowSize, kDropWindowSize); + switch (info.type()) { + case DockInfo::MAXIMIZE: + bounds.Offset(0, kDropWindowSize / 2); + break; + case DockInfo::LEFT_HALF: + bounds.Offset(kDropWindowSize / 2, 0); + break; + case DockInfo::RIGHT_HALF: + bounds.Offset(-kDropWindowSize / 2, 0); + break; + case DockInfo::BOTTOM_HALF: + bounds.Offset(0, -kDropWindowSize / 2); + break; + default: + break; + } + + popup_ = new views::ContainerWin; + popup_->set_window_style(WS_POPUP); + popup_->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW | + WS_EX_TOPMOST); + popup_->SetLayeredAlpha(0x00); + popup_->Init(NULL, bounds, false); + popup_->SetContentsView(new DockView(info.type())); + hot_animation_.Show(); + if (info.in_enable_area()) + enable_animation_.Show(); + popup_->SetWindowPos(HWND_TOP, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE | SWP_SHOWWINDOW); + popup_hwnd_ = popup_->GetHWND(); + } + + ~DockDisplayer() { + if (controller_) + controller_->DockDisplayerDestroyed(this); + } + + // Updates the state based on |in_enable_area|. + void UpdateInEnabledArea(bool in_enable_area) { + if (in_enable_area != in_enable_area_) { + in_enable_area_ = in_enable_area; + if (!in_enable_area_) + enable_animation_.Hide(); + else + enable_animation_.Show(); + } + } + + // Resets the reference to the hosting DraggedTabController. This is invoked + // when the DraggedTabController is destoryed. + void clear_controller() { controller_ = NULL; } + + // HWND of the window we create. + HWND popup_hwnd() { return popup_hwnd_; } + + // Starts the hide animation. When the window is closed the + // DraggedTabController is notified by way of the DockDisplayerDestroyed + // method + void Hide() { + if (hidden_) + return; + + if (!popup_) { + delete this; + return; + } + hidden_ = true; + enable_animation_.Hide(); + hot_animation_.Hide(); + } + + virtual void AnimationProgressed(const Animation* animation) { + popup_->SetLayeredAlpha( + static_cast<BYTE>((hot_animation_.GetCurrentValue() + + enable_animation_.GetCurrentValue()) / 2 * 255.0)); + popup_->GetRootView()->SchedulePaint(); + } + + virtual void AnimationEnded(const Animation* animation) { + if (!hidden_) + return; + popup_->Close(); + delete this; + return; + } + + private: + // DraggedTabController that created us. + DraggedTabController* controller_; + + // Window we're showing. + views::ContainerWin* popup_; + + // HWND of |popup_|. We cache this to avoid the possibility of invoking a + // method on popup_ after we close it. + HWND popup_hwnd_; + + // Animation corresponding to !DockInfo::in_enable_area. + SlideAnimation hot_animation_; + + // Animation corresponding to DockInfo::in_enable_area. + SlideAnimation enable_animation_; + + // Have we been hidden? + bool hidden_; + + // Value of DockInfo::in_enable_area. + bool in_enable_area_; +}; /////////////////////////////////////////////////////////////////////////////// // DraggedTabController, public: @@ -330,10 +508,45 @@ void DraggedTabController::InitWindowCreatePoint() { gfx::Point DraggedTabController::GetWindowCreatePoint() const { POINT pt; GetCursorPos(&pt); + if (dock_info_.type() != DockInfo::NONE) { + // If we're going to dock, we need to return the exact coordinate, + // otherwise we may attempt to maximize on the wrong monitor. + return gfx::Point(pt); + } return gfx::Point(pt.x - window_create_point_.x(), pt.y - window_create_point_.y()); } +void DraggedTabController::UpdateDockInfo(const gfx::Point& screen_point) { + // Update the DockInfo for the current mouse coordinates. + DockInfo dock_info = GetDockInfoAtPoint(screen_point); + if (!dock_info.equals(dock_info_)) { + // DockInfo for current position differs. + if (dock_info_.type() != DockInfo::NONE && + !dock_controllers_.empty()) { + // Hide old visual indicator. + dock_controllers_.back()->Hide(); + } + dock_info_ = dock_info; + if (dock_info_.type() != DockInfo::NONE) { + // Show new docking position. + DockDisplayer* controller = new DockDisplayer(this, dock_info_); + if (controller->popup_hwnd()) { + dock_controllers_.push_back(controller); + dock_windows_.insert(controller->popup_hwnd()); + } else { + delete controller; + } + } + } else if (dock_info_.type() != DockInfo::NONE && + !dock_controllers_.empty()) { + // Current dock position is the same as last, update the controller's + // in_enable_area state as it may have changed. + dock_controllers_.back()->UpdateInEnabledArea(dock_info_.in_enable_area()); + } +} + + void DraggedTabController::ChangeDraggedContents(TabContents* new_contents) { if (dragged_contents_) { NotificationService::current()->RemoveObserver(this, @@ -399,6 +612,9 @@ void DraggedTabController::ContinueDragging() { if (target_tabstrip) Attach(target_tabstrip, screen_point); } + + UpdateDockInfo(screen_point); + MoveTab(screen_point); } @@ -434,21 +650,44 @@ void DraggedTabController::MoveTab(const gfx::Point& screen_point) { view_->MoveTo(dragged_view_point); } +DockInfo DraggedTabController::GetDockInfoAtPoint( + const gfx::Point& screen_point) { + if (attached_tabstrip_) { + // If the mouse is over a tab strip, don't offer a dock position. + return DockInfo(); + } + + if (dock_info_.IsValidForPoint(screen_point)) { + // It's possible any given screen coordinate has multiple docking + // positions. Check the current info first to avoid having the docking + // position bounce around. + return dock_info_; + } + + HWND dragged_hwnd = view_->GetContainer()->GetHWND(); + dock_windows_.insert(dragged_hwnd); + DockInfo info = DockInfo::GetDockInfoAtPoint(screen_point, dock_windows_); + dock_windows_.erase(dragged_hwnd); + return info; +} + TabStrip* DraggedTabController::GetTabStripForPoint( - const gfx::Point& screen_point) const { + const gfx::Point& screen_point) { HWND dragged_hwnd = view_->GetContainer()->GetHWND(); - HWND other_hwnd = WindowFinder::WindowForPoint(screen_point, dragged_hwnd); - if (!other_hwnd) + dock_windows_.insert(dragged_hwnd); + HWND local_window = + DockInfo::GetLocalProcessWindowAtPoint(screen_point, dock_windows_); + dock_windows_.erase(dragged_hwnd); + if (!local_window) + return NULL; + BrowserWindow* browser = BrowserView::GetBrowserWindowForHWND(local_window); + if (!browser) return NULL; - BrowserWindow* other_frame = BrowserView::GetBrowserWindowForHWND(other_hwnd); - if (other_frame) { - TabStrip* other_tabstrip = other_frame->GetTabStrip(); - if (!other_tabstrip->IsCompatibleWith(source_tabstrip_)) - return NULL; - return GetTabStripIfItContains(other_tabstrip, screen_point); - } - return NULL; + TabStrip* other_tabstrip = browser->GetTabStrip(); + if (!other_tabstrip->IsCompatibleWith(source_tabstrip_)) + return NULL; + return GetTabStripIfItContains(other_tabstrip, screen_point); } TabStrip* DraggedTabController::GetTabStripIfItContains( @@ -673,6 +912,16 @@ Tab* DraggedTabController::GetTabMatchingDraggedContents( } void DraggedTabController::EndDragImpl(EndDragType type) { + // Hide the current dock controllers. + for (size_t i = 0; i < dock_controllers_.size(); ++i) { + // Be sure and clear the controller first, that way if Hide ends up + // deleting the controller it won't call us back. + dock_controllers_[i]->clear_controller(); + dock_controllers_[i]->Hide(); + } + dock_controllers_.clear(); + dock_windows_.clear(); + bool destroy_now = true; if (type != TAB_DESTROYED) { // We only finish up the drag if we were actually dragging. If we never @@ -754,14 +1003,61 @@ bool DraggedTabController::CompleteDrag() { NewCallback(this, &DraggedTabController::OnAnimateToBoundsComplete)); destroy_immediately = false; } else { + if (dock_info_.type() != DockInfo::NONE) { + switch (dock_info_.type()) { + case DockInfo::LEFT_OF_WINDOW: + UserMetrics::RecordAction(L"DockingWindow_Left", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::RIGHT_OF_WINDOW: + UserMetrics::RecordAction(L"DockingWindow_Right", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::BOTTOM_OF_WINDOW: + UserMetrics::RecordAction(L"DockingWindow_Bottom", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::TOP_OF_WINDOW: + UserMetrics::RecordAction(L"DockingWindow_Top", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::MAXIMIZE: + UserMetrics::RecordAction(L"DockingWindow_Maximize", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::LEFT_HALF: + UserMetrics::RecordAction(L"DockingWindow_LeftHalf", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::RIGHT_HALF: + UserMetrics::RecordAction(L"DockingWindow_RightHalf", + source_tabstrip_->model()->profile()); + break; + + case DockInfo::BOTTOM_HALF: + UserMetrics::RecordAction(L"DockingWindow_BottomHalf", + source_tabstrip_->model()->profile()); + break; + + default: + NOTREACHED(); + break; + } + } // Compel the model to construct a new window for the detached TabContents. CRect browser_rect; GetWindowRect(source_tabstrip_->GetContainer()->GetHWND(), &browser_rect); gfx::Rect window_bounds( GetWindowCreatePoint(), gfx::Size(browser_rect.Width(), browser_rect.Height())); - source_tabstrip_->model()->TearOffTabContents(dragged_contents_, - window_bounds); + source_tabstrip_->model()->delegate()->CreateNewStripWithContents( + dragged_contents_, window_bounds, dock_info_); CleanUpHiddenFrame(); } @@ -847,3 +1143,20 @@ void DraggedTabController::OnAnimateToBoundsComplete() { source_tabstrip_->DestroyDragController(); } +void DraggedTabController::DockDisplayerDestroyed( + DockDisplayer* controller) { + std::set<HWND>::iterator dock_i = + dock_windows_.find(controller->popup_hwnd()); + if (dock_i != dock_windows_.end()) + dock_windows_.erase(dock_i); + else + NOTREACHED(); + + std::vector<DockDisplayer*>::iterator i = + std::find(dock_controllers_.begin(), dock_controllers_.end(), + controller); + if (i != dock_controllers_.end()) + dock_controllers_.erase(i); + else + NOTREACHED(); +} diff --git a/chrome/browser/views/tabs/dragged_tab_controller.h b/chrome/browser/views/tabs/dragged_tab_controller.h index fb367c3..0363d93 100644 --- a/chrome/browser/views/tabs/dragged_tab_controller.h +++ b/chrome/browser/views/tabs/dragged_tab_controller.h @@ -7,7 +7,9 @@ #include "base/gfx/rect.h" #include "base/message_loop.h" +#include "chrome/browser/dock_info.h" #include "chrome/browser/tab_contents_delegate.h" +#include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/views/tabs/tab_renderer.h" #include "chrome/common/notification_service.h" @@ -15,6 +17,7 @@ namespace views { class MouseEvent; class View; } +class BrowserWindow; class DraggedTabView; class HWNDPhotobooth; class SkBitmap; @@ -65,6 +68,9 @@ class DraggedTabController : public TabContentsDelegate, bool IsDragSourceTab(Tab* tab) const; private: + class DockDisplayer; + friend class DockDisplayer; + // Enumeration of the ways a drag session can end. enum EndDragType { // Drag session exited normally: the user released the mouse. @@ -118,6 +124,8 @@ class DraggedTabController : public TabContentsDelegate, // current mouse position. gfx::Point GetWindowCreatePoint() const; + void UpdateDockInfo(const gfx::Point& screen_point); + // Replaces the TabContents being dragged with the specified |new_contents|. // This can occur if the active TabContents for the tab being dragged is // replaced, e.g. if a transition from one TabContentsType to another occurs @@ -145,7 +153,9 @@ class DraggedTabController : public TabContentsDelegate, // Returns the compatible TabStrip that is under the specified point (screen // coordinates), or NULL if there is none. - TabStrip* GetTabStripForPoint(const gfx::Point& screen_point) const; + TabStrip* GetTabStripForPoint(const gfx::Point& screen_point); + + DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point); // Returns the specified |tabstrip| if it contains the specified point // (screen coordinates), NULL if it does not. @@ -213,6 +223,8 @@ class DraggedTabController : public TabContentsDelegate, // position. void OnAnimateToBoundsComplete(); + void DockDisplayerDestroyed(DockDisplayer* controller); + // The TabContents being dragged. This can get replaced during the drag if // the associated NavigationController is navigated to a different // TabContentsType. @@ -279,8 +291,12 @@ class DraggedTabController : public TabContentsDelegate, // time of the last re-order event. int last_move_screen_x_; + DockInfo dock_info_; + + std::set<HWND> dock_windows_; + std::vector<DockDisplayer*> dock_controllers_; + DISALLOW_COPY_AND_ASSIGN(DraggedTabController); }; #endif // CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_ - diff --git a/chrome/browser/views/tabs/dragged_tab_view.cc b/chrome/browser/views/tabs/dragged_tab_view.cc index 118f89f..6f20c6a 100644 --- a/chrome/browser/views/tabs/dragged_tab_view.cc +++ b/chrome/browser/views/tabs/dragged_tab_view.cc @@ -56,8 +56,7 @@ DraggedTabView::~DraggedTabView() { } void DraggedTabView::MoveTo(const gfx::Point& screen_point) { - if (!container_->IsVisible()) - container_->ShowWindow(SW_SHOWNOACTIVATE); + int show_flags = container_->IsVisible() ? SWP_NOZORDER : SWP_SHOWWINDOW; int x; if (UILayoutIsRightToLeft() && !attached_) { @@ -75,7 +74,8 @@ void DraggedTabView::MoveTo(const gfx::Point& screen_point) { int y = screen_point.y() + mouse_tab_offset_.y() - ScaleValue(mouse_tab_offset_.y()); - container_->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); + container_->SetWindowPos(HWND_TOP, x, y, 0, 0, + SWP_NOSIZE | SWP_NOACTIVATE | show_flags); } void DraggedTabView::Attach(int selected_width) { diff --git a/chrome/common/slide_animation.h b/chrome/common/slide_animation.h index 42e9e65..f690e48 100644 --- a/chrome/common/slide_animation.h +++ b/chrome/common/slide_animation.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_SLIDE_COMMON_ANIMATION_H__ -#define CHROME_SLIDE_COMMON_ANIMATION_H__ +#ifndef CHROME_COMMON_SLIDE_ANIMATION_H_ +#define CHROME_COMMON_SLIDE_ANIMATION_H_ #include "chrome/common/animation.h" @@ -97,5 +97,4 @@ class SlideAnimation : public Animation { int slide_duration_; }; -#endif // CHROME_COMMON_SLIDE_ANIMATION_H__ - +#endif // CHROME_COMMON_SLIDE_ANIMATION_H_ diff --git a/chrome/common/win_util.cc b/chrome/common/win_util.cc index 243d629..aba3aad 100644 --- a/chrome/common/win_util.cc +++ b/chrome/common/win_util.cc @@ -617,7 +617,9 @@ void SetChildBounds(HWND child_window, HWND parent_window, IsWindowVisible(insert_after_window)) window = insert_after_window; - HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST); + POINT window_point = { bounds.x(), bounds.y() }; + HMONITOR monitor = MonitorFromPoint(window_point, + MONITOR_DEFAULTTONEAREST); if (monitor) { MONITORINFO mi = {0}; mi.cbSize = sizeof(mi); |