blob: f0566e65698a2da547373012178c48c81590bcfc [file] [log] [blame]
// Copyright (c) 2011 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/ui/views/tab_contents/native_tab_contents_view_gtk.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"
#include "chrome/browser/ui/gtk/constrained_window_gtk.h"
#include "chrome/browser/ui/gtk/tab_contents_drag_source.h"
#include "chrome/browser/ui/views/tab_contents/native_tab_contents_view_delegate.h"
#include "chrome/browser/ui/views/tab_contents/native_tab_contents_view_views.h"
#include "content/browser/renderer_host/render_widget_host_view_gtk.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "views/views_delegate.h"
using WebKit::WebDragOperation;
using WebKit::WebDragOperationsMask;
using WebKit::WebInputEvent;
namespace {
// Called when the content view gtk widget is tabbed to, or after the call to
// gtk_widget_child_focus() in TakeFocus(). We return true
// and grab focus if we don't have it. The call to
// FocusThroughTabTraversal(bool) forwards the "move focus forward" effect to
// webkit.
gboolean OnFocus(GtkWidget* widget, GtkDirectionType focus,
TabContents* tab_contents) {
// If we already have focus, let the next widget have a shot at it. We will
// reach this situation after the call to gtk_widget_child_focus() in
// TakeFocus().
if (gtk_widget_is_focus(widget))
return FALSE;
gtk_widget_grab_focus(widget);
bool reverse = focus == GTK_DIR_TAB_BACKWARD;
tab_contents->FocusThroughTabTraversal(reverse);
return TRUE;
}
// See tab_contents_view_gtk.cc for discussion of mouse scroll zooming.
gboolean OnMouseScroll(GtkWidget* widget, GdkEventScroll* event,
internal::NativeTabContentsViewDelegate* delegate) {
if ((event->state & gtk_accelerator_get_default_mod_mask()) ==
GDK_CONTROL_MASK) {
if (event->direction == GDK_SCROLL_DOWN) {
delegate->OnNativeTabContentsViewWheelZoom(false);
return TRUE;
}
if (event->direction == GDK_SCROLL_UP) {
delegate->OnNativeTabContentsViewWheelZoom(true);
return TRUE;
}
}
return FALSE;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsViewGtk, public:
NativeTabContentsViewGtk::NativeTabContentsViewGtk(
internal::NativeTabContentsViewDelegate* delegate)
: views::NativeWidgetGtk(delegate->AsNativeWidgetDelegate()),
delegate_(delegate),
ignore_next_char_event_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(drag_source_(
new TabContentsDragSource(delegate->GetTabContents()))) {
}
NativeTabContentsViewGtk::~NativeTabContentsViewGtk() {
delegate_ = NULL;
}
void NativeTabContentsViewGtk::AttachConstrainedWindow(
ConstrainedWindowGtk* constrained_window) {
DCHECK(find(constrained_windows_.begin(), constrained_windows_.end(),
constrained_window) == constrained_windows_.end());
constrained_windows_.push_back(constrained_window);
AddChild(constrained_window->widget());
gfx::Size requested_size;
views::NativeWidgetGtk::GetRequestedSize(&requested_size);
PositionConstrainedWindows(requested_size);
}
void NativeTabContentsViewGtk::RemoveConstrainedWindow(
ConstrainedWindowGtk* constrained_window) {
std::vector<ConstrainedWindowGtk*>::iterator item =
find(constrained_windows_.begin(), constrained_windows_.end(),
constrained_window);
DCHECK(item != constrained_windows_.end());
RemoveChild((*item)->widget());
constrained_windows_.erase(item);
}
////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsViewGtk, NativeTabContentsView implementation:
void NativeTabContentsViewGtk::InitNativeTabContentsView() {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
params.native_widget = this;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
GetWidget()->Init(params);
// We need to own the widget in order to attach/detach the native view to a
// container.
gtk_object_ref(GTK_OBJECT(GetWidget()->GetNativeView()));
}
void NativeTabContentsViewGtk::Unparent() {
}
RenderWidgetHostView* NativeTabContentsViewGtk::CreateRenderWidgetHostView(
RenderWidgetHost* render_widget_host) {
RenderWidgetHostViewGtk* view =
new RenderWidgetHostViewGtk(render_widget_host);
view->InitAsChild();
g_signal_connect(view->native_view(), "focus",
G_CALLBACK(OnFocus), delegate_->GetTabContents());
g_signal_connect(view->native_view(), "scroll-event",
G_CALLBACK(OnMouseScroll), delegate_);
// Let widget know that the tab contents has been painted.
views::NativeWidgetGtk::RegisterChildExposeHandler(view->native_view());
// Renderer target DnD.
if (delegate_->GetTabContents()->ShouldAcceptDragAndDrop())
drag_dest_.reset(new WebDragDestGtk(delegate_->GetTabContents(),
view->native_view()));
gtk_fixed_put(GTK_FIXED(GetWidget()->GetNativeView()), view->native_view(), 0,
0);
return view;
}
gfx::NativeWindow NativeTabContentsViewGtk::GetTopLevelNativeWindow() const {
GtkWidget* window = gtk_widget_get_ancestor(GetWidget()->GetNativeView(),
GTK_TYPE_WINDOW);
return window ? GTK_WINDOW(window) : NULL;
}
void NativeTabContentsViewGtk::SetPageTitle(const std::wstring& title) {
// Set the window name to include the page title so it's easier to spot
// when debugging (e.g. via xwininfo -tree).
if (GDK_IS_WINDOW(GetNativeView()->window))
gdk_window_set_title(GetNativeView()->window, WideToUTF8(title).c_str());
}
void NativeTabContentsViewGtk::StartDragging(const WebDropData& drop_data,
WebKit::WebDragOperationsMask ops,
const SkBitmap& image,
const gfx::Point& image_offset) {
drag_source_->StartDragging(drop_data, ops, &last_mouse_down_,
image, image_offset);
}
void NativeTabContentsViewGtk::CancelDrag() {
}
bool NativeTabContentsViewGtk::IsDoingDrag() const {
return false;
}
void NativeTabContentsViewGtk::SetDragCursor(
WebKit::WebDragOperation operation) {
if (drag_dest_.get())
drag_dest_->UpdateDragStatus(operation);
}
views::NativeWidget* NativeTabContentsViewGtk::AsNativeWidget() {
return this;
}
////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsViewGtk, views::NativeWidgetGtk overrides:
// Called when the mouse moves within the widget. We notify SadTabView if it's
// not NULL, else our delegate.
gboolean NativeTabContentsViewGtk::OnMotionNotify(GtkWidget* widget,
GdkEventMotion* event) {
if (delegate_->IsShowingSadTab())
return views::NativeWidgetGtk::OnMotionNotify(widget, event);
delegate_->OnNativeTabContentsViewMouseMove(true);
return FALSE;
}
gboolean NativeTabContentsViewGtk::OnLeaveNotify(GtkWidget* widget,
GdkEventCrossing* event) {
if (delegate_->IsShowingSadTab())
return views::NativeWidgetGtk::OnLeaveNotify(widget, event);
delegate_->OnNativeTabContentsViewMouseMove(false);
return FALSE;
}
gboolean NativeTabContentsViewGtk::OnButtonPress(GtkWidget* widget,
GdkEventButton* event) {
if (delegate_->IsShowingSadTab())
return views::NativeWidgetGtk::OnButtonPress(widget, event);
last_mouse_down_ = *event;
return views::NativeWidgetGtk::OnButtonPress(widget, event);
}
void NativeTabContentsViewGtk::OnSizeAllocate(GtkWidget* widget,
GtkAllocation* allocation) {
gfx::Size size(allocation->width, allocation->height);
delegate_->OnNativeTabContentsViewSized(size);
if (size != size_)
PositionConstrainedWindows(size);
size_ = size;
views::NativeWidgetGtk::OnSizeAllocate(widget, allocation);
}
void NativeTabContentsViewGtk::OnShow(GtkWidget* widget) {
delegate_->OnNativeTabContentsViewShown();
views::NativeWidgetGtk::OnShow(widget);
}
void NativeTabContentsViewGtk::OnHide(GtkWidget* widget) {
// OnHide can be called during widget destruction (gtk_widget_dispose calls
// gtk_widget_hide) so we make sure we do not call back through to the
// delegate after it's already deleted.
if (delegate_)
delegate_->OnNativeTabContentsViewHidden();
views::NativeWidgetGtk::OnHide(widget);
}
////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsViewGtk, private:
void NativeTabContentsViewGtk::PositionConstrainedWindows(
const gfx::Size& view_size) {
// Place each ConstrainedWindow in the center of the view.
int half_view_width = view_size.width() / 2;
typedef std::vector<ConstrainedWindowGtk*>::iterator iterator;
for (iterator f = constrained_windows_.begin(),
l = constrained_windows_.end(); f != l; ++f) {
GtkWidget* widget = (*f)->widget();
GtkRequisition requisition;
gtk_widget_size_request(widget, &requisition);
int child_x = std::max(half_view_width - (requisition.width / 2), 0);
PositionChild(widget, child_x, 0, 0, 0);
}
}
////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsView, public:
// static
NativeTabContentsView* NativeTabContentsView::CreateNativeTabContentsView(
internal::NativeTabContentsViewDelegate* delegate) {
if (views::Widget::IsPureViews() &&
views::ViewsDelegate::views_delegate->GetDefaultParentView())
return new NativeTabContentsViewViews(delegate);
return new NativeTabContentsViewGtk(delegate);
}