summaryrefslogtreecommitdiffstats
path: root/content/browser/web_contents/web_contents_view_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/web_contents/web_contents_view_win.cc')
-rw-r--r--content/browser/web_contents/web_contents_view_win.cc485
1 files changed, 485 insertions, 0 deletions
diff --git a/content/browser/web_contents/web_contents_view_win.cc b/content/browser/web_contents/web_contents_view_win.cc
new file mode 100644
index 0000000..f5c5c01
--- /dev/null
+++ b/content/browser/web_contents/web_contents_view_win.cc
@@ -0,0 +1,485 @@
+// Copyright (c) 2012 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 "content/browser/web_contents/web_contents_view_win.h"
+
+#include "base/bind.h"
+#include "content/browser/renderer_host/render_view_host_factory.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_win.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/browser/web_contents/interstitial_page_impl.h"
+#include "content/browser/web_contents/web_contents_drag_win.h"
+#include "content/browser/web_contents/web_drag_dest_win.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_view_delegate.h"
+#include "ui/gfx/screen.h"
+
+using content::RenderViewHost;
+using content::RenderWidgetHostView;
+using content::WebContents;
+using content::WebContentsViewDelegate;
+
+namespace {
+
+// We need to have a parent window for the compositing code to work correctly.
+//
+// A tab will not have a parent HWND whenever it is not active in its
+// host window - for example at creation time and when it's in the
+// background, so we provide a default widget to host them.
+//
+// It may be tempting to use GetDesktopWindow() instead, but this is
+// problematic as the shell sends messages to children of the desktop
+// window that interact poorly with us.
+//
+// See: http://crbug.com/16476
+class TempParent : public ui::WindowImpl {
+ public:
+ static TempParent* Get() {
+ static TempParent* g_temp_parent;
+ if (!g_temp_parent) {
+ g_temp_parent = new TempParent();
+
+ g_temp_parent->set_window_style(WS_POPUP);
+ g_temp_parent->set_window_ex_style(WS_EX_TOOLWINDOW);
+ g_temp_parent->Init(GetDesktopWindow(), gfx::Rect());
+ EnableWindow(g_temp_parent->hwnd(), FALSE);
+ }
+ return g_temp_parent;
+ }
+
+ private:
+ // Explicitly do nothing in Close. We do this as some external apps may get a
+ // handle to this window and attempt to close it.
+ void OnClose() {
+ }
+
+ BEGIN_MSG_MAP_EX(WebContentsViewWin)
+ MSG_WM_CLOSE(OnClose)
+ END_MSG_MAP()
+};
+
+} // namespace namespace
+
+WebContentsViewWin::WebContentsViewWin(TabContents* tab_contents,
+ WebContentsViewDelegate* delegate)
+ : tab_contents_(tab_contents),
+ view_(NULL),
+ delegate_(delegate),
+ close_tab_after_drag_ends_(false) {
+}
+
+WebContentsViewWin::~WebContentsViewWin() {
+ if (IsWindow(hwnd()))
+ DestroyWindow(hwnd());
+}
+
+void WebContentsViewWin::CreateView(const gfx::Size& initial_size) {
+ initial_size_ = initial_size;
+
+ set_window_style(WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+
+ Init(TempParent::Get()->hwnd(), gfx::Rect(initial_size_));
+
+ // Remove the root view drop target so we can register our own.
+ RevokeDragDrop(GetNativeView());
+ drag_dest_ = new WebDragDest(hwnd(), tab_contents_);
+ if (delegate_.get()) {
+ content::WebDragDestDelegate* delegate = delegate_->GetDragDestDelegate();
+ if (delegate)
+ drag_dest_->set_delegate(delegate);
+ }
+}
+
+RenderWidgetHostView* WebContentsViewWin::CreateViewForWidget(
+ content::RenderWidgetHost* render_widget_host) {
+ if (render_widget_host->GetView()) {
+ // During testing, the view will already be set up in most cases to the
+ // test view, so we don't want to clobber it with a real one. To verify that
+ // this actually is happening (and somebody isn't accidentally creating the
+ // view twice), we check for the RVH Factory, which will be set when we're
+ // making special ones (which go along with the special views).
+ DCHECK(RenderViewHostFactory::has_factory());
+ return render_widget_host->GetView();
+ }
+
+ view_ = static_cast<RenderWidgetHostViewWin*>(
+ RenderWidgetHostView::CreateViewForWidget(render_widget_host));
+ view_->CreateWnd(GetNativeView());
+ view_->ShowWindow(SW_SHOW);
+ view_->SetSize(initial_size_);
+ return view_;
+}
+
+gfx::NativeView WebContentsViewWin::GetNativeView() const {
+ return hwnd();
+}
+
+gfx::NativeView WebContentsViewWin::GetContentNativeView() const {
+ RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
+ return rwhv ? rwhv->GetNativeView() : NULL;
+}
+
+gfx::NativeWindow WebContentsViewWin::GetTopLevelNativeWindow() const {
+ return GetParent(GetNativeView());
+}
+
+void WebContentsViewWin::GetContainerBounds(gfx::Rect *out) const {
+ // Copied from NativeWidgetWin::GetClientAreaScreenBounds().
+ RECT r;
+ GetClientRect(hwnd(), &r);
+ POINT point = { r.left, r.top };
+ ClientToScreen(hwnd(), &point);
+ *out = gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top);
+}
+
+void WebContentsViewWin::SetPageTitle(const string16& title) {
+ // It's possible to get this after the hwnd has been destroyed.
+ if (GetNativeView())
+ ::SetWindowText(GetNativeView(), title.c_str());
+}
+
+void WebContentsViewWin::OnTabCrashed(base::TerminationStatus status,
+ int error_code) {
+ // TODO(avi): No other TCV implementation does anything in this callback. Can
+ // this be moved elsewhere so that |OnTabCrashed| can be removed everywhere?
+ view_ = NULL;
+}
+
+void WebContentsViewWin::SizeContents(const gfx::Size& size) {
+ gfx::Rect bounds;
+ GetContainerBounds(&bounds);
+ if (bounds.size() != size) {
+ SetWindowPos(hwnd(), NULL, 0, 0, size.width(), size.height(),
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
+ } else {
+ // Our size matches what we want but the renderers size may not match.
+ // Pretend we were resized so that the renderers size is updated too.
+ if (tab_contents_->GetInterstitialPage())
+ tab_contents_->GetInterstitialPage()->SetSize(size);
+ RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
+ if (rwhv)
+ rwhv->SetSize(size);
+ }
+}
+
+void WebContentsViewWin::RenderViewCreated(RenderViewHost* host) {
+}
+
+void WebContentsViewWin::Focus() {
+ if (tab_contents_->GetInterstitialPage()) {
+ tab_contents_->GetInterstitialPage()->Focus();
+ return;
+ }
+
+ if (delegate_.get() && delegate_->Focus())
+ return;
+
+ RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
+ if (rwhv)
+ rwhv->Focus();
+}
+
+void WebContentsViewWin::SetInitialFocus() {
+ if (tab_contents_->FocusLocationBarByDefault())
+ tab_contents_->SetFocusToLocationBar(false);
+ else
+ Focus();
+}
+
+void WebContentsViewWin::StoreFocus() {
+ if (delegate_.get())
+ delegate_->StoreFocus();
+}
+
+void WebContentsViewWin::RestoreFocus() {
+ if (delegate_.get())
+ delegate_->RestoreFocus();
+}
+
+bool WebContentsViewWin::IsDoingDrag() const {
+ return drag_handler_.get() != NULL;
+}
+
+void WebContentsViewWin::CancelDragAndCloseTab() {
+ DCHECK(IsDoingDrag());
+ // We can't close the tab while we're in the drag and
+ // |drag_handler_->CancelDrag()| is async. Instead, set a flag to cancel
+ // the drag and when the drag nested message loop ends, close the tab.
+ drag_handler_->CancelDrag();
+ close_tab_after_drag_ends_ = true;
+}
+
+bool WebContentsViewWin::IsEventTracking() const {
+ return false;
+}
+
+void WebContentsViewWin::CloseTabAfterEventTracking() {
+}
+
+void WebContentsViewWin::GetViewBounds(gfx::Rect* out) const {
+ RECT r;
+ GetWindowRect(hwnd(), &r);
+ *out = gfx::Rect(r);
+}
+
+void WebContentsViewWin::CreateNewWindow(
+ int route_id,
+ const ViewHostMsg_CreateWindow_Params& params) {
+ web_contents_view_helper_.CreateNewWindow(tab_contents_, route_id, params);
+}
+
+void WebContentsViewWin::CreateNewWidget(int route_id,
+ WebKit::WebPopupType popup_type) {
+ web_contents_view_helper_.CreateNewWidget(tab_contents_,
+ route_id,
+ false,
+ popup_type);
+}
+
+void WebContentsViewWin::CreateNewFullscreenWidget(int route_id) {
+ web_contents_view_helper_.CreateNewWidget(tab_contents_,
+ route_id,
+ true,
+ WebKit::WebPopupTypeNone);
+}
+
+void WebContentsViewWin::ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {
+ web_contents_view_helper_.ShowCreatedWindow(
+ tab_contents_, route_id, disposition, initial_pos, user_gesture);
+}
+
+void WebContentsViewWin::ShowCreatedWidget(int route_id,
+ const gfx::Rect& initial_pos) {
+ web_contents_view_helper_.ShowCreatedWidget(tab_contents_,
+ route_id,
+ false,
+ initial_pos);
+}
+
+void WebContentsViewWin::ShowCreatedFullscreenWidget(int route_id) {
+ web_contents_view_helper_.ShowCreatedWidget(tab_contents_,
+ route_id,
+ true,
+ gfx::Rect());
+}
+
+void WebContentsViewWin::ShowContextMenu(
+ const content::ContextMenuParams& params) {
+ // Allow WebContentsDelegates to handle the context menu operation first.
+ if (tab_contents_->GetDelegate() &&
+ tab_contents_->GetDelegate()->HandleContextMenu(params)) {
+ return;
+ }
+
+ if (delegate_.get())
+ delegate_->ShowContextMenu(params);
+}
+
+void WebContentsViewWin::ShowPopupMenu(const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<WebMenuItem>& items,
+ bool right_aligned) {
+ // External popup menus are only used on Mac.
+ NOTIMPLEMENTED();
+}
+
+void WebContentsViewWin::StartDragging(const WebDropData& drop_data,
+ WebKit::WebDragOperationsMask operations,
+ const SkBitmap& image,
+ const gfx::Point& image_offset) {
+ drag_handler_ = new WebContentsDragWin(
+ GetNativeView(),
+ tab_contents_,
+ drag_dest_,
+ base::Bind(&WebContentsViewWin::EndDragging, base::Unretained(this)));
+ drag_handler_->StartDragging(drop_data, operations, image, image_offset);
+}
+
+void WebContentsViewWin::UpdateDragCursor(WebKit::WebDragOperation operation) {
+ drag_dest_->set_drag_cursor(operation);
+}
+
+void WebContentsViewWin::GotFocus() {
+ if (tab_contents_->GetDelegate())
+ tab_contents_->GetDelegate()->WebContentsFocused(tab_contents_);
+}
+
+void WebContentsViewWin::TakeFocus(bool reverse) {
+ if (tab_contents_->GetDelegate() &&
+ !tab_contents_->GetDelegate()->TakeFocus(reverse) &&
+ delegate_.get()) {
+ delegate_->TakeFocus(reverse);
+ }
+}
+
+void WebContentsViewWin::EndDragging() {
+ drag_handler_ = NULL;
+ if (close_tab_after_drag_ends_) {
+ close_tab_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(0),
+ this, &WebContentsViewWin::CloseTab);
+ }
+ tab_contents_->SystemDragEnded();
+}
+
+void WebContentsViewWin::CloseTab() {
+ RenderViewHost* rvh = tab_contents_->GetRenderViewHost();
+ rvh->GetDelegate()->Close(rvh);
+}
+
+LRESULT WebContentsViewWin::OnDestroy(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ if (drag_dest_.get()) {
+ RevokeDragDrop(GetNativeView());
+ drag_dest_ = NULL;
+ }
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnWindowPosChanged(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(lparam);
+ if (window_pos->flags & SWP_HIDEWINDOW) {
+ tab_contents_->HideContents();
+ return 0;
+ }
+
+ // The TabContents was shown by a means other than the user selecting a
+ // Tab, e.g. the window was minimized then restored.
+ if (window_pos->flags & SWP_SHOWWINDOW)
+ tab_contents_->ShowContents();
+
+ // Unless we were specifically told not to size, cause the renderer to be
+ // sized to the new bounds, which forces a repaint. Not required for the
+ // simple minimize-restore case described above, for example, since the
+ // size hasn't changed.
+ if (window_pos->flags & SWP_NOSIZE)
+ return 0;
+
+ gfx::Size size(window_pos->cx, window_pos->cy);
+ if (tab_contents_->GetInterstitialPage())
+ tab_contents_->GetInterstitialPage()->SetSize(size);
+ RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
+ if (rwhv)
+ rwhv->SetSize(size);
+
+ if (delegate_.get())
+ delegate_->SizeChanged(size);
+
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnMouseDown(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // Make sure this TabContents is activated when it is clicked on.
+ if (tab_contents_->GetDelegate())
+ tab_contents_->GetDelegate()->ActivateContents(tab_contents_);
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnMouseMove(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // Let our delegate know that the mouse moved (useful for resetting status
+ // bubble state).
+ if (tab_contents_->GetDelegate()) {
+ tab_contents_->GetDelegate()->ContentsMouseEvent(
+ tab_contents_, gfx::Screen::GetCursorScreenPoint(), true);
+ }
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnReflectedMessage(
+ UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ MSG* message = reinterpret_cast<MSG*>(lparam);
+ switch (message->message) {
+ case WM_MOUSEWHEEL:
+ // This message is reflected from the view() to this window.
+ if (GET_KEYSTATE_WPARAM(message->wParam) & MK_CONTROL) {
+ tab_contents_->GetDelegate()->ContentsZoomChange(
+ GET_WHEEL_DELTA_WPARAM(message->wParam) > 0);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnNCCalcSize(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // Hack for ThinkPad mouse wheel driver. We have set the fake scroll bars
+ // to receive scroll messages from ThinkPad touch-pad driver. Suppress
+ // painting of scrollbars by returning 0 size for them.
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnScroll(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ int scroll_type = LOWORD(wparam);
+ short position = HIWORD(wparam);
+ HWND scrollbar = reinterpret_cast<HWND>(lparam);
+ // This window can receive scroll events as a result of the ThinkPad's
+ // touch-pad scroll wheel emulation.
+ // If ctrl is held, zoom the UI. There are three issues with this:
+ // 1) Should the event be eaten or forwarded to content? We eat the event,
+ // which is like Firefox and unlike IE.
+ // 2) Should wheel up zoom in or out? We zoom in (increase font size), which
+ // is like IE and Google maps, but unlike Firefox.
+ // 3) Should the mouse have to be over the content area? We zoom as long as
+ // content has focus, although FF and IE require that the mouse is over
+ // content. This is because all events get forwarded when content has
+ // focus.
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
+ int distance = 0;
+ switch (scroll_type) {
+ case SB_LINEUP:
+ distance = WHEEL_DELTA;
+ break;
+ case SB_LINEDOWN:
+ distance = -WHEEL_DELTA;
+ break;
+ // TODO(joshia): Handle SB_PAGEUP, SB_PAGEDOWN, SB_THUMBPOSITION,
+ // and SB_THUMBTRACK for completeness
+ default:
+ break;
+ }
+
+ tab_contents_->GetDelegate()->ContentsZoomChange(distance > 0);
+ return 0;
+ }
+
+ // Reflect scroll message to the view() to give it a chance
+ // to process scrolling.
+ SendMessage(GetContentNativeView(), message, wparam, lparam);
+ return 0;
+}
+
+LRESULT WebContentsViewWin::OnSize(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // NOTE: Because we handle OnWindowPosChanged without calling DefWindowProc,
+ // OnSize is NOT called on window resize. This handler is called only once
+ // when the window is created.
+ // Don't call base class OnSize to avoid useless layout for 0x0 size.
+ // We will get OnWindowPosChanged later and layout root view in WasSized.
+
+ // Hack for ThinkPad touch-pad driver.
+ // Set fake scrollbars so that we can get scroll messages,
+ SCROLLINFO si = {0};
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+
+ si.nMin = 1;
+ si.nMax = 100;
+ si.nPage = 10;
+ si.nPos = 50;
+
+ ::SetScrollInfo(hwnd(), SB_HORZ, &si, FALSE);
+ ::SetScrollInfo(hwnd(), SB_VERT, &si, FALSE);
+
+ return 1;
+}