diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-05 20:04:04 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-05 20:04:04 +0000 |
commit | 179caa6698de49c762ace7ecc8728d642222f8b9 (patch) | |
tree | 718fef5e6b13967dddc9bfade97224622924525b | |
parent | c88a70fe5a69daf5d3d6e0599ed273d160b55c41 (diff) | |
download | chromium_src-179caa6698de49c762ace7ecc8728d642222f8b9.zip chromium_src-179caa6698de49c762ace7ecc8728d642222f8b9.tar.gz chromium_src-179caa6698de49c762ace7ecc8728d642222f8b9.tar.bz2 |
Refactors HWNDView into two classes for reuse on GTK.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/108025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15327 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | chrome/views/controls/hwnd_view.cc | 207 | ||||
-rw-r--r-- | chrome/views/controls/hwnd_view.h | 58 | ||||
-rw-r--r-- | chrome/views/controls/native_view_host.cc | 74 | ||||
-rw-r--r-- | chrome/views/controls/native_view_host.h | 103 | ||||
-rw-r--r-- | chrome/views/views.vcproj | 8 |
6 files changed, 278 insertions, 174 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 8804cf7..5fe5813 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2879,6 +2879,8 @@ 'views/controls/native_control.h', 'views/controls/native_control_win.cc', 'views/controls/native_control_win.h', + 'views/controls/native_view_host.cc', + 'views/controls/native_view_host.h', 'views/controls/scroll_view.cc', 'views/controls/scroll_view.h', 'views/controls/scrollbar/bitmap_scroll_bar.cc', diff --git a/chrome/views/controls/hwnd_view.cc b/chrome/views/controls/hwnd_view.cc index bc8a7eb..b6ff61b 100644 --- a/chrome/views/controls/hwnd_view.cc +++ b/chrome/views/controls/hwnd_view.cc @@ -7,7 +7,6 @@ #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/win_util.h" #include "chrome/views/focus/focus_manager.h" -#include "chrome/views/controls/scroll_view.h" #include "chrome/views/widget/widget.h" #include "base/logging.h" @@ -15,173 +14,125 @@ namespace views { static const char kViewClassName[] = "chrome/views/HWNDView"; -HWNDView::HWNDView() : - hwnd_(0), - installed_clip_(false), - fast_resize_(false), - focus_view_(NULL) { - // HWNDs are placed relative to the root. As such, we need to - // know when the position of any ancestor changes, or our visibility relative - // to other views changed as it'll effect our position relative to the root. - SetNotifyWhenVisibleBoundsInRootChanges(true); +HWNDView::HWNDView() { } HWNDView::~HWNDView() { } void HWNDView::Attach(HWND hwnd) { - DCHECK(hwnd_ == NULL); + DCHECK(native_view() == NULL); DCHECK(hwnd) << "Impossible detatched tab case; See crbug.com/6316"; - hwnd_ = hwnd; + set_native_view(hwnd); // First hide the new window. We don't want anything to draw (like sub-hwnd // borders), when we change the parent below. - ShowWindow(hwnd_, SW_HIDE); + ShowWindow(hwnd, SW_HIDE); // Need to set the HWND's parent before changing its size to avoid flashing. - ::SetParent(hwnd_, GetWidget()->GetNativeView()); + ::SetParent(hwnd, GetWidget()->GetNativeView()); Layout(); // Register with the focus manager so the associated view is focused when the // native control gets the focus. - FocusManager::InstallFocusSubclass(hwnd_, focus_view_ ? focus_view_ : this); + FocusManager::InstallFocusSubclass( + hwnd, associated_focus_view() ? associated_focus_view() : this); } void HWNDView::Detach() { - DCHECK(hwnd_); - FocusManager::UninstallFocusSubclass(hwnd_); - hwnd_ = NULL; - installed_clip_ = false; + DCHECK(native_view()); + FocusManager::UninstallFocusSubclass(native_view()); + set_native_view(NULL); + set_installed_clip(false); } -void HWNDView::SetAssociatedFocusView(View* view) { - DCHECK(!::IsWindow(hwnd_)); - focus_view_ = view; +void HWNDView::Paint(ChromeCanvas* canvas) { + // The area behind our window is black, so during a fast resize (where our + // content doesn't draw over the full size of our HWND, and the HWND + // background color doesn't show up), we need to cover that blackness with + // something so that fast resizes don't result in black flash. + // + // It would be nice if this used some approximation of the page's + // current background color. + if (installed_clip()) + canvas->FillRectInt(SkColorSetRGB(255, 255, 255), 0, 0, width(), height()); } -HWND HWNDView::GetHWND() const { - return hwnd_; +std::string HWNDView::GetClassName() const { + return kViewClassName; } -void HWNDView::Layout() { - if (!hwnd_) +void HWNDView::ViewHierarchyChanged(bool is_add, View *parent, View *child) { + if (!native_view()) return; - // Since HWNDs know nothing about the View hierarchy (they are direct - // children of the Widget that hosts our View hierarchy) they need to be - // positioned in the coordinate system of the Widget, not the current - // view. - gfx::Point top_left; - ConvertPointToWidget(this, &top_left); - - gfx::Rect vis_bounds = GetVisibleBounds(); - bool visible = !vis_bounds.IsEmpty(); - - if (visible && !fast_resize_) { - if (vis_bounds.size() != size()) { - // Only a portion of the HWND is really visible. - int x = vis_bounds.x(); - int y = vis_bounds.y(); - HRGN clip_region = CreateRectRgn(x, y, x + vis_bounds.width(), - y + vis_bounds.height()); - // NOTE: SetWindowRgn owns the region (as well as the deleting the - // current region), as such we don't delete the old region. - SetWindowRgn(hwnd_, clip_region, FALSE); - installed_clip_ = true; - } else if (installed_clip_) { - // The whole HWND is visible but we installed a clip on the HWND, - // uninstall it. - SetWindowRgn(hwnd_, 0, FALSE); - installed_clip_ = false; - } - } - - if (visible) { - UINT swp_flags; - swp_flags = SWP_DEFERERASE | - SWP_NOACTIVATE | - SWP_NOCOPYBITS | - SWP_NOOWNERZORDER | - SWP_NOZORDER; - // Only send the SHOWWINDOW flag if we're invisible, to avoid flashing. - if (!::IsWindowVisible(hwnd_)) - swp_flags = (swp_flags | SWP_SHOWWINDOW) & ~SWP_NOREDRAW; - - if (fast_resize_) { - // In a fast resize, we move the window and clip it with SetWindowRgn. - CRect rect; - GetWindowRect(hwnd_, &rect); - ::SetWindowPos(hwnd_, 0, top_left.x(), top_left.y(), rect.Width(), - rect.Height(), swp_flags); - - HRGN clip_region = CreateRectRgn(0, 0, width(), height()); - SetWindowRgn(hwnd_, clip_region, FALSE); - installed_clip_ = true; - } else { - ::SetWindowPos(hwnd_, 0, top_left.x(), top_left.y(), width(), height(), - swp_flags); - } - } else if (::IsWindowVisible(hwnd_)) { - // The window is currently visible, but its clipped by another view. Hide - // it. - ::SetWindowPos(hwnd_, 0, 0, 0, 0, 0, - SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | - SWP_NOREDRAW | SWP_NOOWNERZORDER); + Widget* widget = GetWidget(); + if (is_add && widget) { + HWND parent_hwnd = ::GetParent(native_view()); + HWND widget_hwnd = widget->GetNativeView(); + if (parent_hwnd != widget_hwnd) + ::SetParent(native_view(), widget_hwnd); + if (IsVisibleInRootView()) + ::ShowWindow(native_view(), SW_SHOW); + else + ::ShowWindow(native_view(), SW_HIDE); + Layout(); + } else if (!is_add) { + ::ShowWindow(native_view(), SW_HIDE); + ::SetParent(native_view(), NULL); } } -void HWNDView::VisibilityChanged(View* starting_from, bool is_visible) { - Layout(); +void HWNDView::Focus() { + ::SetFocus(native_view()); } -gfx::Size HWNDView::GetPreferredSize() { - return preferred_size_; +void HWNDView::InstallClip(int x, int y, int w, int h) { + HRGN clip_region = CreateRectRgn(x, y, x + w, y + h); + // NOTE: SetWindowRgn owns the region (as well as the deleting the + // current region), as such we don't delete the old region. + SetWindowRgn(native_view(), clip_region, FALSE); } -void HWNDView::ViewHierarchyChanged(bool is_add, View *parent, View *child) { - if (hwnd_) { - Widget* widget = GetWidget(); - if (is_add && widget) { - HWND parent_hwnd = ::GetParent(hwnd_); - HWND widget_hwnd = widget->GetNativeView(); - if (parent_hwnd != widget_hwnd) { - ::SetParent(hwnd_, widget_hwnd); - } - if (IsVisibleInRootView()) - ::ShowWindow(hwnd_, SW_SHOW); - else - ::ShowWindow(hwnd_, SW_HIDE); - Layout(); - } else if (!is_add) { - ::ShowWindow(hwnd_, SW_HIDE); - ::SetParent(hwnd_, NULL); - } - } +void HWNDView::UninstallClip() { + SetWindowRgn(native_view(), 0, FALSE); } -void HWNDView::VisibleBoundsInRootChanged() { - Layout(); +void HWNDView::ShowWidget(int x, int y, int w, int h) { + UINT swp_flags = SWP_DEFERERASE | + SWP_NOACTIVATE | + SWP_NOCOPYBITS | + SWP_NOOWNERZORDER | + SWP_NOZORDER; + // Only send the SHOWWINDOW flag if we're invisible, to avoid flashing. + if (!::IsWindowVisible(native_view())) + swp_flags = (swp_flags | SWP_SHOWWINDOW) & ~SWP_NOREDRAW; + + if (fast_resize()) { + // In a fast resize, we move the window and clip it with SetWindowRgn. + CRect rect; + GetWindowRect(native_view(), &rect); + ::SetWindowPos(native_view(), 0, x, y, rect.Width(), rect.Height(), + swp_flags); + + HRGN clip_region = CreateRectRgn(0, 0, w, h); + SetWindowRgn(native_view(), clip_region, FALSE); + set_installed_clip(true); + } else { + ::SetWindowPos(native_view(), 0, x, y, w, h, swp_flags); + } } -void HWNDView::Focus() { - ::SetFocus(hwnd_); -} +void HWNDView::HideWidget() { + if (!::IsWindowVisible(native_view())) + return; // Currently not visible, nothing to do. -void HWNDView::Paint(ChromeCanvas* canvas) { - // The area behind our window is black, so during a fast resize (where our - // content doesn't draw over the full size of our HWND, and the HWND - // background color doesn't show up), we need to cover that blackness with - // something so that fast resizes don't result in black flash. - // - // It would be nice if this used some approximation of the page's - // current background color. - if (installed_clip_) - canvas->FillRectInt(SkColorSetRGB(255, 255, 255), 0, 0, width(), height()); -} - -std::string HWNDView::GetClassName() const { - return kViewClassName; + // The window is currently visible, but its clipped by another view. Hide + // it. + ::SetWindowPos(native_view(), 0, 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | + SWP_NOREDRAW | SWP_NOOWNERZORDER); } } // namespace views diff --git a/chrome/views/controls/hwnd_view.h b/chrome/views/controls/hwnd_view.h index 4667212..fc08b5d5 100644 --- a/chrome/views/controls/hwnd_view.h +++ b/chrome/views/controls/hwnd_view.h @@ -7,7 +7,7 @@ #include <string> -#include "chrome/views/view.h" +#include "chrome/views/controls/native_view_host.h" namespace views { @@ -21,15 +21,12 @@ namespace views { // within thew View hierarchy and benefit from the sizing/layout. // ///////////////////////////////////////////////////////////////////////////// -class HWNDView : public View { +// TODO: Rename this to NativeViewHostWin. +class HWNDView : public NativeViewHost { public: HWNDView(); virtual ~HWNDView(); - virtual gfx::Size GetPreferredSize(); - - void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; } - // Attach a window handle to this View, making the window it represents // subject to sizing according to this View's parent container's Layout // Manager's sizing heuristics. @@ -41,58 +38,27 @@ class HWNDView : public View { // Detach the attached window handle. It will no longer be updated void Detach(); - virtual void VisibilityChanged(View* starting_from, bool is_visible); - - HWND GetHWND() const; - - virtual void Layout(); + // TODO(sky): convert this to native_view(). + HWND GetHWND() const { return native_view(); } virtual void Paint(ChromeCanvas* canvas); // Overridden from View. virtual std::string GetClassName() const; - // A HWNDView has an associated focus View so that the focus of the native - // control and of the View are kept in sync. In simple cases where the - // HWNDView directly wraps a native window as is, the associated view is this - // View. In other cases where the HWNDView is part of another view (such as - // TextField), the actual View is not the HWNDView and this method must be - // called to set that. - // This method must be called before Attach(). - void SetAssociatedFocusView(View* view); - - void set_fast_resize(bool fast_resize) { fast_resize_ = fast_resize; } - protected: virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); - // Notification that our visible bounds relative to the root has changed. - // This updates the bounds of the HWND. - virtual void VisibleBoundsInRootChanged(); - virtual void Focus(); + // NativeHostView overrides. + virtual void InstallClip(int x, int y, int w, int h); + virtual void UninstallClip(); + virtual void ShowWidget(int x, int y, int w, int h); + virtual void HideWidget(); + private: - // The hosted window handle. - HWND hwnd_; - - // The preferred size of this View - gfx::Size preferred_size_; - - // Have we installed a region on the HWND used to clip to only the visible - // portion of the HWND? - bool installed_clip_; - - // Fast resizing will move the hwnd and clip its window region, this will - // result in white areas and will not resize the content (so scrollbars - // will be all wrong and content will flow offscreen). Only use this - // when you're doing extremely quick, high-framerate vertical resizes - // and don't care about accuracy. Make sure you do a real resize at the - // end. USE WITH CAUTION. - bool fast_resize_; - - // The view that should be given focus when this HWNDView is focused. - View* focus_view_; + DISALLOW_COPY_AND_ASSIGN(HWNDView); }; } // namespace views diff --git a/chrome/views/controls/native_view_host.cc b/chrome/views/controls/native_view_host.cc new file mode 100644 index 0000000..525aa497 --- /dev/null +++ b/chrome/views/controls/native_view_host.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2009 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/views/controls/native_view_host.h" + +#include "chrome/views/widget/widget.h" +#include "base/logging.h" + +namespace views { + +NativeViewHost::NativeViewHost() + : native_view_(NULL), + installed_clip_(false), + fast_resize_(false), + focus_view_(NULL) { + // The native widget is placed relative to the root. As such, we need to + // know when the position of any ancestor changes, or our visibility relative + // to other views changed as it'll effect our position relative to the root. + SetNotifyWhenVisibleBoundsInRootChanges(true); +} + +NativeViewHost::~NativeViewHost() { +} + +gfx::Size NativeViewHost::GetPreferredSize() { + return preferred_size_; +} + +void NativeViewHost::Layout() { + if (!native_view_) + return; + + // Since widgets know nothing about the View hierarchy (they are direct + // children of the Widget that hosts our View hierarchy) they need to be + // positioned in the coordinate system of the Widget, not the current + // view. + gfx::Point top_left; + ConvertPointToWidget(this, &top_left); + + gfx::Rect vis_bounds = GetVisibleBounds(); + bool visible = !vis_bounds.IsEmpty(); + + if (visible && !fast_resize_) { + if (vis_bounds.size() != size()) { + // Only a portion of the Widget is really visible. + int x = vis_bounds.x(); + int y = vis_bounds.y(); + InstallClip(x, y, vis_bounds.width(), vis_bounds.height()); + installed_clip_ = true; + } else if (installed_clip_) { + // The whole widget is visible but we installed a clip on the widget, + // uninstall it. + UninstallClip(); + installed_clip_ = false; + } + } + + if (visible) { + ShowWidget(top_left.x(), top_left.y(), width(), height()); + } else { + HideWidget(); + } +} + +void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) { + Layout(); +} + +void NativeViewHost::VisibleBoundsInRootChanged() { + Layout(); +} + +} // namespace views diff --git a/chrome/views/controls/native_view_host.h b/chrome/views/controls/native_view_host.h new file mode 100644 index 0000000..e1e123f --- /dev/null +++ b/chrome/views/controls/native_view_host.h @@ -0,0 +1,103 @@ +// Copyright (c) 2009 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_VIEWS_CONTROLS_NATIVE_VIEW_HOST_H_ +#define CHROME_VIEWS_CONTROLS_NATIVE_VIEW_HOST_H_ + +#include <string> + +#include "chrome/views/view.h" + +#include "base/gfx/native_widget_types.h" + +namespace views { + +// Base class for embedding native widgets in a view. +class NativeViewHost : public View { + public: + NativeViewHost(); + virtual ~NativeViewHost(); + + void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; } + + // Returns the preferred size set via set_preferred_size. + virtual gfx::Size GetPreferredSize(); + + // Overriden to invoke Layout. + virtual void VisibilityChanged(View* starting_from, bool is_visible); + + // Invokes any of InstallClip, UninstallClip, ShowWidget or HideWidget + // depending upon what portion of the widget is view in the parent. + virtual void Layout(); + + // A NativeViewHost has an associated focus View so that the focus of the + // native control and of the View are kept in sync. In simple cases where the + // NativeViewHost directly wraps a native window as is, the associated view + // is this View. In other cases where the NativeViewHost is part of another + // view (such as TextField), the actual View is not the NativeViewHost and + // this method must be called to set that. + // This method must be called before Attach(). + void SetAssociatedFocusView(View* view) { focus_view_ = view; } + View* associated_focus_view() { return focus_view_; } + + void set_fast_resize(bool fast_resize) { fast_resize_ = fast_resize; } + bool fast_resize() const { return fast_resize_; } + + // The embedded native view. + gfx::NativeView native_view() const { return native_view_; } + + protected: + // Notification that our visible bounds relative to the root has changed. + // Invokes Layout to make sure the widget is positioned correctly. + virtual void VisibleBoundsInRootChanged(); + + // Sets the native view. Subclasses will typically invoke Layout after setting + // the widget. + void set_native_view(gfx::NativeView widget) { native_view_ = widget; } + + // Installs a clip on the native widget. + virtual void InstallClip(int x, int y, int w, int h) = 0; + + // Removes the clip installed on the native widget by way of InstallClip. + virtual void UninstallClip() = 0; + + // Shows the widget at the specified position (relative to the parent widget). + virtual void ShowWidget(int x, int y, int w, int h) = 0; + + // Hides the widget. NOTE: this may be invoked when the widget is already + // hidden. + virtual void HideWidget() = 0; + + void set_installed_clip(bool installed_clip) { + installed_clip_ = installed_clip; + } + bool installed_clip() const { return installed_clip_; } + + private: + gfx::NativeView native_view_; + + // The preferred size of this View + gfx::Size preferred_size_; + + // Have we installed a region on the HWND used to clip to only the visible + // portion of the HWND? + bool installed_clip_; + + // Fast resizing will move the hwnd and clip its window region, this will + // result in white areas and will not resize the content (so scrollbars + // will be all wrong and content will flow offscreen). Only use this + // when you're doing extremely quick, high-framerate vertical resizes + // and don't care about accuracy. Make sure you do a real resize at the + // end. USE WITH CAUTION. + bool fast_resize_; + + // The view that should be given focus when this NativeViewHost is focused. + View* focus_view_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewHost); +}; + +} // namespace views + +#endif // CHROME_VIEWS_CONTROLS_NATIVE_VIEW_HOST_H_ diff --git a/chrome/views/views.vcproj b/chrome/views/views.vcproj index 0aba6df..8e5d2fe 100644 --- a/chrome/views/views.vcproj +++ b/chrome/views/views.vcproj @@ -511,6 +511,14 @@ > </File> <File + RelativePath=".\controls\native_view_host.cc" + > + </File> + <File + RelativePath=".\controls\native_view_host.h" + > + </File> + <File RelativePath=".\controls\scroll_view.cc" > </File> |