| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/views/controls/native/native_view_host.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "ui/base/cursor/cursor.h" | |
| 9 #include "ui/gfx/canvas.h" | |
| 10 #include "ui/views/accessibility/native_view_accessibility.h" | |
| 11 #include "ui/views/controls/native/native_view_host_wrapper.h" | |
| 12 #include "ui/views/widget/widget.h" | |
| 13 | |
| 14 namespace views { | |
| 15 | |
| 16 // static | |
| 17 const char NativeViewHost::kViewClassName[] = "NativeViewHost"; | |
| 18 const char kWidgetNativeViewHostKey[] = "WidgetNativeViewHost"; | |
| 19 | |
| 20 //////////////////////////////////////////////////////////////////////////////// | |
| 21 // NativeViewHost, public: | |
| 22 | |
| 23 NativeViewHost::NativeViewHost() | |
| 24 : native_view_(NULL), | |
| 25 fast_resize_(false), | |
| 26 fast_resize_at_last_layout_(false), | |
| 27 focus_view_(NULL) { | |
| 28 } | |
| 29 | |
| 30 NativeViewHost::~NativeViewHost() { | |
| 31 } | |
| 32 | |
| 33 void NativeViewHost::Attach(gfx::NativeView native_view) { | |
| 34 DCHECK(native_view); | |
| 35 DCHECK(!native_view_); | |
| 36 native_view_ = native_view; | |
| 37 // If set_focus_view() has not been invoked, this view is the one that should | |
| 38 // be seen as focused when the native view receives focus. | |
| 39 if (!focus_view_) | |
| 40 focus_view_ = this; | |
| 41 native_wrapper_->AttachNativeView(); | |
| 42 Layout(); | |
| 43 | |
| 44 Widget* widget = Widget::GetWidgetForNativeView(native_view); | |
| 45 if (widget) | |
| 46 widget->SetNativeWindowProperty(kWidgetNativeViewHostKey, this); | |
| 47 } | |
| 48 | |
| 49 void NativeViewHost::Detach() { | |
| 50 Detach(false); | |
| 51 } | |
| 52 | |
| 53 void NativeViewHost::SetPreferredSize(const gfx::Size& size) { | |
| 54 preferred_size_ = size; | |
| 55 PreferredSizeChanged(); | |
| 56 } | |
| 57 | |
| 58 void NativeViewHost::NativeViewDestroyed() { | |
| 59 // Detach so we can clear our state and notify the native_wrapper_ to release | |
| 60 // ref on the native view. | |
| 61 Detach(true); | |
| 62 } | |
| 63 | |
| 64 //////////////////////////////////////////////////////////////////////////////// | |
| 65 // NativeViewHost, View overrides: | |
| 66 | |
| 67 gfx::Size NativeViewHost::GetPreferredSize() const { | |
| 68 return preferred_size_; | |
| 69 } | |
| 70 | |
| 71 void NativeViewHost::Layout() { | |
| 72 if (!native_view_ || !native_wrapper_.get()) | |
| 73 return; | |
| 74 | |
| 75 gfx::Rect vis_bounds = GetVisibleBounds(); | |
| 76 bool visible = !vis_bounds.IsEmpty(); | |
| 77 | |
| 78 if (visible && !fast_resize_) { | |
| 79 if (vis_bounds.size() != size()) { | |
| 80 // Only a portion of the Widget is really visible. | |
| 81 int x = vis_bounds.x(); | |
| 82 int y = vis_bounds.y(); | |
| 83 native_wrapper_->InstallClip(x, y, vis_bounds.width(), | |
| 84 vis_bounds.height()); | |
| 85 } else if (native_wrapper_->HasInstalledClip()) { | |
| 86 // The whole widget is visible but we installed a clip on the widget, | |
| 87 // uninstall it. | |
| 88 native_wrapper_->UninstallClip(); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 if (visible) { | |
| 93 // Since widgets know nothing about the View hierarchy (they are direct | |
| 94 // children of the Widget that hosts our View hierarchy) they need to be | |
| 95 // positioned in the coordinate system of the Widget, not the current | |
| 96 // view. Also, they should be positioned respecting the border insets | |
| 97 // of the native view. | |
| 98 gfx::Rect local_bounds = ConvertRectToWidget(GetContentsBounds()); | |
| 99 native_wrapper_->ShowWidget(local_bounds.x(), local_bounds.y(), | |
| 100 local_bounds.width(), | |
| 101 local_bounds.height()); | |
| 102 } else { | |
| 103 native_wrapper_->HideWidget(); | |
| 104 } | |
| 105 fast_resize_at_last_layout_ = visible && fast_resize_; | |
| 106 } | |
| 107 | |
| 108 void NativeViewHost::OnPaint(gfx::Canvas* canvas) { | |
| 109 // Paint background if there is one. NativeViewHost needs to paint | |
| 110 // a background when it is hosted in a TabbedPane. For Gtk implementation, | |
| 111 // NativeTabbedPaneGtk uses a NativeWidgetGtk as page container and because | |
| 112 // NativeWidgetGtk hook "expose" with its root view's paint, we need to | |
| 113 // fill the content. Otherwise, the tab page's background is not properly | |
| 114 // cleared. For Windows case, it appears okay to not paint background because | |
| 115 // we don't have a container window in-between. However if you want to use | |
| 116 // customized background, then this becomes necessary. | |
| 117 OnPaintBackground(canvas); | |
| 118 | |
| 119 // The area behind our window is black, so during a fast resize (where our | |
| 120 // content doesn't draw over the full size of our native view, and the native | |
| 121 // view background color doesn't show up), we need to cover that blackness | |
| 122 // with something so that fast resizes don't result in black flash. | |
| 123 // | |
| 124 // It would be nice if this used some approximation of the page's | |
| 125 // current background color. | |
| 126 if (native_wrapper_->HasInstalledClip()) | |
| 127 canvas->FillRect(GetLocalBounds(), SK_ColorWHITE); | |
| 128 } | |
| 129 | |
| 130 void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) { | |
| 131 Layout(); | |
| 132 } | |
| 133 | |
| 134 bool NativeViewHost::GetNeedsNotificationWhenVisibleBoundsChange() const { | |
| 135 // The native widget is placed relative to the root. As such, we need to | |
| 136 // know when the position of any ancestor changes, or our visibility relative | |
| 137 // to other views changed as it'll effect our position relative to the root. | |
| 138 return true; | |
| 139 } | |
| 140 | |
| 141 void NativeViewHost::OnVisibleBoundsChanged() { | |
| 142 Layout(); | |
| 143 } | |
| 144 | |
| 145 void NativeViewHost::ViewHierarchyChanged( | |
| 146 const ViewHierarchyChangedDetails& details) { | |
| 147 views::Widget* this_widget = GetWidget(); | |
| 148 | |
| 149 // A non-NULL |details.move_view| indicates a move operation i.e. |this| is | |
| 150 // is being reparented. If the previous and new parents belong to the same | |
| 151 // widget, don't remove |this| from the widget. This saves resources from | |
| 152 // removing from widget and immediately followed by adding to widget; in | |
| 153 // particular, there wouldn't be spurious visibilitychange events for web | |
| 154 // contents of |WebView|. | |
| 155 if (details.move_view && this_widget && | |
| 156 details.move_view->GetWidget() == this_widget) { | |
| 157 return; | |
| 158 } | |
| 159 | |
| 160 if (details.is_add && this_widget) { | |
| 161 if (!native_wrapper_.get()) | |
| 162 native_wrapper_.reset(NativeViewHostWrapper::CreateWrapper(this)); | |
| 163 native_wrapper_->AddedToWidget(); | |
| 164 } else if (!details.is_add) { | |
| 165 native_wrapper_->RemovedFromWidget(); | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 const char* NativeViewHost::GetClassName() const { | |
| 170 return kViewClassName; | |
| 171 } | |
| 172 | |
| 173 void NativeViewHost::OnFocus() { | |
| 174 native_wrapper_->SetFocus(); | |
| 175 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); | |
| 176 } | |
| 177 | |
| 178 gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() { | |
| 179 if (native_wrapper_.get()) { | |
| 180 gfx::NativeViewAccessible accessible_view = | |
| 181 native_wrapper_->GetNativeViewAccessible(); | |
| 182 if (accessible_view) | |
| 183 return accessible_view; | |
| 184 } | |
| 185 | |
| 186 return View::GetNativeViewAccessible(); | |
| 187 } | |
| 188 | |
| 189 gfx::NativeCursor NativeViewHost::GetCursor(const ui::MouseEvent& event) { | |
| 190 return native_wrapper_->GetCursor(event.x(), event.y()); | |
| 191 } | |
| 192 | |
| 193 //////////////////////////////////////////////////////////////////////////////// | |
| 194 // NativeViewHost, private: | |
| 195 | |
| 196 void NativeViewHost::Detach(bool destroyed) { | |
| 197 if (native_view_) { | |
| 198 if (!destroyed) { | |
| 199 Widget* widget = Widget::GetWidgetForNativeView(native_view_); | |
| 200 if (widget) | |
| 201 widget->SetNativeWindowProperty(kWidgetNativeViewHostKey, NULL); | |
| 202 ClearFocus(); | |
| 203 } | |
| 204 native_wrapper_->NativeViewDetaching(destroyed); | |
| 205 native_view_ = NULL; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 void NativeViewHost::ClearFocus() { | |
| 210 FocusManager* focus_manager = GetFocusManager(); | |
| 211 if (!focus_manager || !focus_manager->GetFocusedView()) | |
| 212 return; | |
| 213 | |
| 214 Widget::Widgets widgets; | |
| 215 Widget::GetAllChildWidgets(native_view(), &widgets); | |
| 216 for (Widget::Widgets::iterator i = widgets.begin(); i != widgets.end(); ++i) { | |
| 217 focus_manager->ViewRemoved((*i)->GetRootView()); | |
| 218 if (!focus_manager->GetFocusedView()) | |
| 219 return; | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 } // namespace views | |
| OLD | NEW |