summaryrefslogtreecommitdiffstats
path: root/chrome/browser/tab_contents
diff options
context:
space:
mode:
authoryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-17 03:14:12 +0000
committeryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-17 03:14:12 +0000
commita87e9acee988e8136b3ff74a8d5dda7047565308 (patch)
treed0350b0b1e3de0e2597f5e3aba751a256514d03e /chrome/browser/tab_contents
parent1ff3c23680621228ea756e1acde0ede0f5baabbb (diff)
downloadchromium_src-a87e9acee988e8136b3ff74a8d5dda7047565308.zip
chromium_src-a87e9acee988e8136b3ff74a8d5dda7047565308.tar.gz
chromium_src-a87e9acee988e8136b3ff74a8d5dda7047565308.tar.bz2
Do not write a profile path on a BookmarkDragData object since a dragged url (javascript:...) on a web page does not belong to (the profile's) bookmark model.
Currently the following function returns DRAG_NONE and thus the drop operation is not accepted. The reason for the return value is because ops becomes DragDropTypes::DRAG_MOVE (since data.profile_path_ is not empty()) but event.GetSourceOperations() returns DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK. int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event, ... int ops = data.GetFirstNode(profile_) ? DragDropTypes::DRAG_MOVE : DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK; return bookmark_utils::PreferredDropOperation(event.GetSourceOperations(), ops); BUG=12290 TEST=Open http://delicious.com/help/bookmarklets page and drag the "Bookmark on Delicious" link on "Google Chrome" section to the bookmark bar. Review URL: http://codereview.chromium.org/125111 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18584 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/tab_contents')
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_win.cc617
1 files changed, 617 insertions, 0 deletions
diff --git a/chrome/browser/tab_contents/tab_contents_view_win.cc b/chrome/browser/tab_contents/tab_contents_view_win.cc
new file mode 100644
index 0000000..6ebdb37
--- /dev/null
+++ b/chrome/browser/tab_contents/tab_contents_view_win.cc
@@ -0,0 +1,617 @@
+// 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/tab_contents/tab_contents_view_win.h"
+
+#include <windows.h>
+
+#include "app/gfx/canvas.h"
+#include "app/os_exchange_data.h"
+#include "chrome/browser/bookmarks/bookmark_drag_data.h"
+#include "chrome/browser/browser.h" // TODO(beng): this dependency is awful.
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_request_manager.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host_factory.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_win.h"
+#include "chrome/browser/tab_contents/render_view_context_menu_win.h"
+#include "chrome/browser/tab_contents/interstitial_page.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/tab_contents/web_drag_source.h"
+#include "chrome/browser/tab_contents/web_drop_target.h"
+#include "chrome/browser/views/sad_tab_view.h"
+#include "chrome/common/url_constants.h"
+#include "net/base/net_util.h"
+#include "views/focus/view_storage.h"
+#include "views/widget/root_view.h"
+#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+#include "webkit/glue/webdropdata.h"
+
+using WebKit::WebInputEvent;
+
+namespace {
+
+// Windows callback for OnDestroy to detach the plugin windows.
+BOOL CALLBACK DetachPluginWindowsCallback(HWND window, LPARAM param) {
+ if (WebPluginDelegateImpl::IsPluginDelegateWindow(window) &&
+ !IsHungAppWindow(window)) {
+ ::ShowWindow(window, SW_HIDE);
+ SetParent(window, NULL);
+ }
+ return TRUE;
+}
+
+} // namespace
+
+// static
+TabContentsView* TabContentsView::Create(TabContents* tab_contents) {
+ return new TabContentsViewWin(tab_contents);
+}
+
+TabContentsViewWin::TabContentsViewWin(TabContents* tab_contents)
+ : TabContentsView(tab_contents),
+ ignore_next_char_event_(false) {
+ last_focused_view_storage_id_ =
+ views::ViewStorage::GetSharedInstance()->CreateStorageID();
+}
+
+TabContentsViewWin::~TabContentsViewWin() {
+ // Makes sure to remove any stored view we may still have in the ViewStorage.
+ //
+ // It is possible the view went away before us, so we only do this if the
+ // view is registered.
+ views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
+ view_storage->RemoveView(last_focused_view_storage_id_);
+}
+
+void TabContentsViewWin::CreateView() {
+ set_delete_on_destroy(false);
+ // Since we create these windows parented to the desktop window initially, we
+ // don't want to create them initially visible.
+ set_window_style(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ WidgetWin::Init(GetDesktopWindow(), gfx::Rect(), false);
+
+ // Remove the root view drop target so we can register our own.
+ RevokeDragDrop(GetNativeView());
+ drop_target_ = new WebDropTarget(GetNativeView(), tab_contents());
+}
+
+RenderWidgetHostView* TabContentsViewWin::CreateViewForWidget(
+ RenderWidgetHost* render_widget_host) {
+ if (render_widget_host->view()) {
+ // 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->view();
+ }
+
+ RenderWidgetHostViewWin* view =
+ new RenderWidgetHostViewWin(render_widget_host);
+ view->Create(GetNativeView());
+ view->ShowWindow(SW_SHOW);
+ return view;
+}
+
+gfx::NativeView TabContentsViewWin::GetNativeView() const {
+ return WidgetWin::GetNativeView();
+}
+
+gfx::NativeView TabContentsViewWin::GetContentNativeView() const {
+ if (!tab_contents()->render_widget_host_view())
+ return NULL;
+ return tab_contents()->render_widget_host_view()->GetNativeView();
+}
+
+gfx::NativeWindow TabContentsViewWin::GetTopLevelNativeWindow() const {
+ return ::GetAncestor(GetNativeView(), GA_ROOT);
+}
+
+void TabContentsViewWin::GetContainerBounds(gfx::Rect* out) const {
+ GetBounds(out, false);
+}
+
+void TabContentsViewWin::StartDragging(const WebDropData& drop_data) {
+ scoped_refptr<OSExchangeData> data(new OSExchangeData);
+
+ // TODO(tc): Generate an appropriate drag image.
+
+ // We set the file contents before the URL because the URL also sets file
+ // contents (to a .URL shortcut). We want to prefer file content data over a
+ // shortcut so we add it first.
+ if (!drop_data.file_contents.empty()) {
+ // Images without ALT text will only have a file extension so we need to
+ // synthesize one from the provided extension and URL.
+ FilePath file_name(drop_data.file_description_filename);
+ file_name = file_name.BaseName().RemoveExtension();
+ if (file_name.value().empty()) {
+ // Retrieve the name from the URL.
+ file_name = FilePath::FromWStringHack(
+ net::GetSuggestedFilename(drop_data.url, "", "", L""));
+ }
+ file_name = file_name.ReplaceExtension(drop_data.file_extension);
+ data->SetFileContents(file_name.value(), drop_data.file_contents);
+ }
+ if (!drop_data.text_html.empty())
+ data->SetHtml(drop_data.text_html, drop_data.html_base_url);
+ if (drop_data.url.is_valid()) {
+ if (drop_data.url.SchemeIs(chrome::kJavaScriptScheme)) {
+ // We don't want to allow javascript URLs to be dragged to the desktop,
+ // but we do want to allow them to be added to the bookmarks bar
+ // (bookmarklets). So we create a fake bookmark entry (BookmarkDragData
+ // object) which explorer.exe cannot handle, and write the entry to data.
+ BookmarkDragData::Element bm_elt;
+ bm_elt.is_url = true;
+ bm_elt.url = drop_data.url;
+ bm_elt.title = drop_data.url_title;
+
+ BookmarkDragData bm_drag_data;
+ bm_drag_data.elements.push_back(bm_elt);
+
+ // Pass in NULL as the profile so that the bookmark always adds the url
+ // rather than trying to move an existing url.
+ bm_drag_data.Write(NULL, data);
+ } else {
+ data->SetURL(drop_data.url, drop_data.url_title);
+ }
+ }
+ if (!drop_data.plain_text.empty())
+ data->SetString(drop_data.plain_text);
+
+ scoped_refptr<WebDragSource> drag_source(
+ new WebDragSource(GetNativeView(), tab_contents()->render_view_host()));
+
+ DWORD effects;
+
+ // We need to enable recursive tasks on the message loop so we can get
+ // updates while in the system DoDragDrop loop.
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ DoDragDrop(data, drag_source, DROPEFFECT_COPY | DROPEFFECT_LINK, &effects);
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
+
+ if (tab_contents()->render_view_host())
+ tab_contents()->render_view_host()->DragSourceSystemDragEnded();
+}
+
+void TabContentsViewWin::OnContentsDestroy() {
+ // TODO(brettw) this seems like maybe it can be moved into OnDestroy and this
+ // function can be deleted? If you're adding more here, consider whether it
+ // can be moved into OnDestroy which is a Windows message handler as the
+ // window is being torn down.
+
+ // When a tab is closed all its child plugin windows are destroyed
+ // automatically. This happens before plugins get any notification that its
+ // instances are tearing down.
+ //
+ // Plugins like Quicktime assume that their windows will remain valid as long
+ // as they have plugin instances active. Quicktime crashes in this case
+ // because its windowing code cleans up an internal data structure that the
+ // handler for NPP_DestroyStream relies on.
+ //
+ // The fix is to detach plugin windows from web contents when it is going
+ // away. This will prevent the plugin windows from getting destroyed
+ // automatically. The detached plugin windows will get cleaned up in proper
+ // sequence as part of the usual cleanup when the plugin instance goes away.
+ EnumChildWindows(GetNativeView(), DetachPluginWindowsCallback, NULL);
+}
+
+void TabContentsViewWin::OnDestroy() {
+ if (drop_target_.get()) {
+ RevokeDragDrop(GetNativeView());
+ drop_target_ = NULL;
+ }
+}
+
+void TabContentsViewWin::SetPageTitle(const std::wstring& title) {
+ if (GetNativeView()) {
+ // It's possible to get this after the hwnd has been destroyed.
+ ::SetWindowText(GetNativeView(), title.c_str());
+ // TODO(brettw) this call seems messy the way it reaches into the widget
+ // view, and I'm not sure it's necessary. Maybe we should just remove it.
+ ::SetWindowText(
+ tab_contents()->render_widget_host_view()->GetNativeView(),
+ title.c_str());
+ }
+}
+
+void TabContentsViewWin::OnTabCrashed() {
+ // Force an invalidation to render sad tab. We will notice we crashed when we
+ // paint.
+ // Note that it's possible to get this message after the window was destroyed.
+ if (::IsWindow(GetNativeView()))
+ InvalidateRect(GetNativeView(), NULL, FALSE);
+}
+
+void TabContentsViewWin::SizeContents(const gfx::Size& size) {
+ // TODO(brettw) this is a hack and should be removed. See tab_contents_view.h.
+ WasSized(size);
+}
+
+void TabContentsViewWin::Focus() {
+ HWND container_hwnd = GetNativeView();
+ if (!container_hwnd)
+ return;
+
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManager(container_hwnd);
+ if (!focus_manager)
+ return; // During testing we have no focus manager.
+ views::View* v = focus_manager->GetViewForWindow(container_hwnd, true);
+ DCHECK(v);
+ if (v)
+ v->RequestFocus();
+}
+
+void TabContentsViewWin::SetInitialFocus() {
+ if (tab_contents()->FocusLocationBarByDefault())
+ tab_contents()->delegate()->SetFocusToLocationBar();
+ else
+ ::SetFocus(GetNativeView());
+}
+
+void TabContentsViewWin::StoreFocus() {
+ views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+
+ if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
+ view_storage->RemoveView(last_focused_view_storage_id_);
+
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManager(GetNativeView());
+ if (focus_manager) {
+ // |focus_manager| can be NULL if the tab has been detached but still
+ // exists.
+ views::View* focused_view = focus_manager->GetFocusedView();
+ if (focused_view)
+ view_storage->StoreView(last_focused_view_storage_id_, focused_view);
+
+ // If the focus was on the page, explicitly clear the focus so that we
+ // don't end up with the focused HWND not part of the window hierarchy.
+ // TODO(brettw) this should move to the view somehow.
+ HWND container_hwnd = GetNativeView();
+ if (container_hwnd) {
+ views::View* focused_view = focus_manager->GetFocusedView();
+ if (focused_view) {
+ HWND hwnd = focused_view->GetRootView()->GetWidget()->GetNativeView();
+ if (container_hwnd == hwnd || ::IsChild(container_hwnd, hwnd))
+ focus_manager->ClearFocus();
+ }
+ }
+ }
+}
+
+void TabContentsViewWin::RestoreFocus() {
+ views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::View* last_focused_view =
+ view_storage->RetrieveView(last_focused_view_storage_id_);
+
+ if (!last_focused_view) {
+ SetInitialFocus();
+ } else {
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManager(GetNativeView());
+
+ // If you hit this DCHECK, please report it to Jay (jcampan).
+ DCHECK(focus_manager != NULL) << "No focus manager when restoring focus.";
+
+ if (last_focused_view->IsFocusable() && focus_manager &&
+ focus_manager->ContainsView(last_focused_view)) {
+ last_focused_view->RequestFocus();
+ } else {
+ // The focused view may not belong to the same window hierarchy (e.g.
+ // if the location bar was focused and the tab is dragged out), or it may
+ // no longer be focusable (e.g. if the location bar was focused and then
+ // we switched to fullscreen mode). In that case we default to the
+ // default focus.
+ SetInitialFocus();
+ }
+ view_storage->RemoveView(last_focused_view_storage_id_);
+ }
+}
+
+void TabContentsViewWin::UpdateDragCursor(bool is_drop_target) {
+ drop_target_->set_is_drop_target(is_drop_target);
+}
+
+void TabContentsViewWin::TakeFocus(bool reverse) {
+ if (!tab_contents()->delegate()->TakeFocus(reverse)) {
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManager(GetNativeView());
+
+ // We may not have a focus manager if the tab has been switched before this
+ // message arrived.
+ if (focus_manager)
+ focus_manager->AdvanceFocus(reverse);
+ }
+}
+
+void TabContentsViewWin::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ // Previous calls to TranslateMessage can generate CHAR events as well as
+ // RAW_KEY_DOWN events, even if the latter triggered an accelerator. In these
+ // cases, we discard the CHAR events.
+ if (event.type == WebInputEvent::Char && ignore_next_char_event_) {
+ ignore_next_char_event_ = false;
+ return;
+ }
+ ignore_next_char_event_ = false;
+
+ // The renderer returned a keyboard event it did not process. This may be
+ // a keyboard shortcut that we have to process.
+ if (event.type == WebInputEvent::RawKeyDown) {
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManager(GetNativeView());
+ // We may not have a focus_manager at this point (if the tab has been
+ // switched by the time this message returned).
+ if (focus_manager) {
+ views::Accelerator accelerator(event.windowsKeyCode,
+ (event.modifiers & WebInputEvent::ShiftKey) ==
+ WebInputEvent::ShiftKey,
+ (event.modifiers & WebInputEvent::ControlKey) ==
+ WebInputEvent::ControlKey,
+ (event.modifiers & WebInputEvent::AltKey) ==
+ WebInputEvent::AltKey);
+
+ // This is tricky: we want to set ignore_next_char_event_ if
+ // ProcessAccelerator returns true. But ProcessAccelerator might delete
+ // |this| if the accelerator is a "close tab" one. So we speculatively
+ // set the flag and fix it if no event was handled.
+ ignore_next_char_event_ = true;
+ if (focus_manager->ProcessAccelerator(accelerator)) {
+ // DANGER: |this| could be deleted now!
+ return;
+ } else {
+ // ProcessAccelerator didn't handle the accelerator, so we know both
+ // that |this| is still valid, and that we didn't want to set the flag.
+ ignore_next_char_event_ = false;
+ }
+ }
+ }
+
+ // Any unhandled keyboard/character messages should be defproced.
+ // This allows stuff like Alt+F4, etc to work correctly.
+ DefWindowProc(event.os_event.hwnd,
+ event.os_event.message,
+ event.os_event.wParam,
+ event.os_event.lParam);
+}
+
+void TabContentsViewWin::ShowContextMenu(const ContextMenuParams& params) {
+ RenderViewContextMenuWin menu(tab_contents(),
+ params,
+ GetNativeView());
+
+ POINT screen_pt = { params.x, params.y };
+ MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_pt, 1);
+
+ // Enable recursive tasks on the message loop so we can get updates while
+ // the context menu is being displayed.
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ menu.RunMenuAt(screen_pt.x, screen_pt.y);
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
+}
+
+void TabContentsViewWin::OnHScroll(int scroll_type, short position,
+ HWND scrollbar) {
+ ScrollCommon(WM_HSCROLL, scroll_type, position, scrollbar);
+}
+
+void TabContentsViewWin::OnMouseLeave() {
+ // Let our delegate know that the mouse moved (useful for resetting status
+ // bubble state).
+ if (tab_contents()->delegate())
+ tab_contents()->delegate()->ContentsMouseEvent(tab_contents(), false);
+ SetMsgHandled(FALSE);
+}
+
+LRESULT TabContentsViewWin::OnMouseRange(UINT msg,
+ WPARAM w_param, LPARAM l_param) {
+ switch (msg) {
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN: {
+ // Make sure this TabContents is activated when it is clicked on.
+ if (tab_contents()->delegate())
+ tab_contents()->delegate()->ActivateContents(tab_contents());
+ break;
+ }
+ case WM_MOUSEMOVE:
+ // Let our delegate know that the mouse moved (useful for resetting status
+ // bubble state).
+ if (tab_contents()->delegate()) {
+ tab_contents()->delegate()->ContentsMouseEvent(tab_contents(), true);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void TabContentsViewWin::OnPaint(HDC junk_dc) {
+ if (tab_contents()->render_view_host() &&
+ !tab_contents()->render_view_host()->IsRenderViewLive()) {
+ if (!sad_tab_.get())
+ sad_tab_.reset(new SadTabView);
+ CRect cr;
+ GetClientRect(&cr);
+ sad_tab_->SetBounds(gfx::Rect(cr));
+ gfx::CanvasPaint canvas(GetNativeView(), true);
+ sad_tab_->ProcessPaint(&canvas);
+ return;
+ }
+
+ // We need to do this to validate the dirty area so we don't end up in a
+ // WM_PAINTstorm that causes other mysterious bugs (such as WM_TIMERs not
+ // firing etc). It doesn't matter that we don't have any non-clipped area.
+ CPaintDC dc(GetNativeView());
+ SetMsgHandled(FALSE);
+}
+
+// A message is reflected here from view().
+// Return non-zero to indicate that it is handled here.
+// Return 0 to allow view() to further process it.
+LRESULT TabContentsViewWin::OnReflectedMessage(UINT msg, WPARAM w_param,
+ LPARAM l_param) {
+ MSG* message = reinterpret_cast<MSG*>(l_param);
+ switch (message->message) {
+ case WM_MOUSEWHEEL:
+ // This message is reflected from the view() to this window.
+ if (GET_KEYSTATE_WPARAM(message->wParam) & MK_CONTROL) {
+ WheelZoom(GET_WHEEL_DELTA_WPARAM(message->wParam));
+ return 1;
+ }
+ break;
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ if (ScrollZoom(LOWORD(message->wParam)))
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void TabContentsViewWin::OnSetFocus(HWND window) {
+ // TODO(jcampan): figure out why removing this prevents tabs opened in the
+ // background from properly taking focus.
+ // We NULL-check the render_view_host_ here because Windows can send us
+ // messages during the destruction process after it has been destroyed.
+ if (tab_contents()->render_widget_host_view()) {
+ HWND inner_hwnd =
+ tab_contents()->render_widget_host_view()->GetNativeView();
+ if (::IsWindow(inner_hwnd))
+ ::SetFocus(inner_hwnd);
+ }
+}
+
+void TabContentsViewWin::OnVScroll(int scroll_type, short position,
+ HWND scrollbar) {
+ ScrollCommon(WM_VSCROLL, scroll_type, position, scrollbar);
+}
+
+void TabContentsViewWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
+ if (window_pos->flags & SWP_HIDEWINDOW) {
+ WasHidden();
+ } else {
+ // 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)
+ WasShown();
+
+ // 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))
+ WasSized(gfx::Size(window_pos->cx, window_pos->cy));
+ }
+}
+
+void TabContentsViewWin::OnSize(UINT param, const CSize& size) {
+ WidgetWin::OnSize(param, size);
+
+ // Hack for thinkpad touchpad 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(GetNativeView(), SB_HORZ, &si, FALSE);
+ ::SetScrollInfo(GetNativeView(), SB_VERT, &si, FALSE);
+}
+
+LRESULT TabContentsViewWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) {
+ // Hack for thinkpad mouse wheel driver. We have set the fake scroll bars
+ // to receive scroll messages from thinkpad touchpad driver. Suppress
+ // painting of scrollbars by returning 0 size for them.
+ return 0;
+}
+
+void TabContentsViewWin::OnNCPaint(HRGN rgn) {
+ // Suppress default WM_NCPAINT handling. We don't need to do anything
+ // here since the view will draw everything correctly.
+}
+
+void TabContentsViewWin::ScrollCommon(UINT message, int scroll_type,
+ short position, HWND scrollbar) {
+ // This window can receive scroll events as a result of the ThinkPad's
+ // Trackpad scroll wheel emulation.
+ if (!ScrollZoom(scroll_type)) {
+ // Reflect scroll message to the view() to give it a chance
+ // to process scrolling.
+ SendMessage(GetContentNativeView(), message,
+ MAKELONG(scroll_type, position),
+ reinterpret_cast<LPARAM>(scrollbar));
+ }
+}
+
+void TabContentsViewWin::WasHidden() {
+ tab_contents()->HideContents();
+}
+
+void TabContentsViewWin::WasShown() {
+ tab_contents()->ShowContents();
+}
+
+void TabContentsViewWin::WasSized(const gfx::Size& size) {
+ if (tab_contents()->interstitial_page())
+ tab_contents()->interstitial_page()->SetSize(size);
+ if (tab_contents()->render_widget_host_view())
+ tab_contents()->render_widget_host_view()->SetSize(size);
+
+ // TODO(brettw) this function can probably be moved to this class.
+ tab_contents()->RepositionSupressedPopupsToFit();
+}
+
+bool TabContentsViewWin::ScrollZoom(int scroll_type) {
+ // 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;
+ }
+
+ WheelZoom(distance);
+ return true;
+ }
+ return false;
+}
+
+void TabContentsViewWin::WheelZoom(int distance) {
+ if (tab_contents()->delegate()) {
+ bool zoom_in = distance > 0;
+ tab_contents()->delegate()->ContentsZoomChange(zoom_in);
+ }
+}