Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / tab_contents / chrome_web_contents_view_delegate_gtk.cc
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 "chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.h"
6
7 #include <map>
8
9 #include "base/lazy_instance.h"
10 #include "chrome/browser/browser_shutdown.h"
11 #include "chrome/browser/ui/gtk/constrained_window_gtk.h"
12 #include "chrome/browser/ui/gtk/tab_contents/render_view_context_menu_gtk.h"
13 #include "chrome/browser/ui/gtk/tab_contents/web_drag_bookmark_handler_gtk.h"
14 #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/render_widget_host_view.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_contents_view.h"
20 #include "ui/base/gtk/focus_store_gtk.h"
21 #include "ui/base/gtk/gtk_floating_container.h"
22
23 namespace {
24
25 const char kViewDelegateUserDataKey[] = "ChromeWebContentsViewDelegateGtk";
26
27 class ViewDelegateUserData : public base::SupportsUserData::Data {
28  public:
29   explicit ViewDelegateUserData(ChromeWebContentsViewDelegateGtk* view_delegate)
30       : view_delegate_(view_delegate) {}
31   virtual ~ViewDelegateUserData() {}
32   ChromeWebContentsViewDelegateGtk* view_delegate() { return view_delegate_; }
33
34  private:
35   ChromeWebContentsViewDelegateGtk* view_delegate_;  // unowned
36 };
37
38 }  // namespace
39
40 ChromeWebContentsViewDelegateGtk* ChromeWebContentsViewDelegateGtk::GetFor(
41     content::WebContents* web_contents) {
42   ViewDelegateUserData* user_data = static_cast<ViewDelegateUserData*>(
43       web_contents->GetUserData(&kViewDelegateUserDataKey));
44
45   return user_data ? user_data->view_delegate() : NULL;
46 }
47
48 ChromeWebContentsViewDelegateGtk::ChromeWebContentsViewDelegateGtk(
49     content::WebContents* web_contents)
50     : floating_(gtk_floating_container_new()),
51       web_contents_modal_dialog_(NULL),
52       web_contents_(web_contents),
53       expanded_container_(NULL),
54       focus_store_(NULL) {
55   g_object_ref_sink(floating_.get());
56   gtk_widget_set_name(floating_.get(), "chrome-tab-contents-view");
57   g_signal_connect(floating_.get(), "set-floating-position",
58                    G_CALLBACK(OnSetFloatingPositionThunk), this);
59
60   // Stash this in the WebContents.
61   web_contents->SetUserData(&kViewDelegateUserDataKey,
62                             new ViewDelegateUserData(this));
63 }
64
65 ChromeWebContentsViewDelegateGtk::~ChromeWebContentsViewDelegateGtk() {
66 }
67
68 void ChromeWebContentsViewDelegateGtk::AttachWebContentsModalDialog(
69     GtkWidget* web_contents_modal_dialog) {
70   DCHECK(web_contents_modal_dialog_ == NULL);
71
72   web_contents_modal_dialog_ = web_contents_modal_dialog;
73   gtk_floating_container_add_floating(GTK_FLOATING_CONTAINER(floating_.get()),
74                                       web_contents_modal_dialog);
75 }
76
77 void ChromeWebContentsViewDelegateGtk::RemoveWebContentsModalDialog(
78     GtkWidget* web_contents_modal_dialog) {
79   DCHECK(web_contents_modal_dialog == web_contents_modal_dialog_);
80
81   web_contents_modal_dialog_ = NULL;
82 }
83
84 void ChromeWebContentsViewDelegateGtk::Initialize(
85     GtkWidget* expanded_container, ui::FocusStoreGtk* focus_store) {
86   expanded_container_ = expanded_container;
87   focus_store_ = focus_store;
88   // We install a chrome specific handler to intercept bookmark drags for the
89   // bookmark manager/extension API.
90   bookmark_handler_gtk_.reset(new WebDragBookmarkHandlerGtk);
91
92   gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_container);
93   gtk_widget_show(floating_.get());
94 }
95
96 gfx::NativeView ChromeWebContentsViewDelegateGtk::GetNativeView() const {
97   return floating_.get();
98 }
99
100 void ChromeWebContentsViewDelegateGtk::Focus() {
101   if (!web_contents_modal_dialog_) {
102     GtkWidget* widget = web_contents_->GetView()->GetContentNativeView();
103     if (widget)
104       gtk_widget_grab_focus(widget);
105   }
106 }
107
108 gboolean ChromeWebContentsViewDelegateGtk::OnNativeViewFocusEvent(
109     GtkWidget* widget,
110     GtkDirectionType type,
111     gboolean* return_value) {
112   // If we are showing a web contents modal dialog, don't allow the native view
113   // to take focus.
114   if (web_contents_modal_dialog_) {
115     // If we return false, it will revert to the default handler, which will
116     // take focus. We don't want that. But if we return true, the event will
117     // stop being propagated, leaving focus wherever it is currently. That is
118     // also bad. So we return false to let the default handler run, but take
119     // focus first so as to trick it into thinking the view was already focused
120     // and allowing the event to propagate.
121     gtk_widget_grab_focus(widget);
122     *return_value = FALSE;
123     return TRUE;
124   }
125
126   // Let the default WebContentsViewGtk::OnFocus() behaviour run.
127   return FALSE;
128 }
129
130 void ChromeWebContentsViewDelegateGtk::ShowContextMenu(
131     content::RenderFrameHost* render_frame_host,
132     const content::ContextMenuParams& params) {
133   // Find out the RenderWidgetHostView that corresponds to the render widget on
134   // which this context menu is showed, so that we can retrieve the last mouse
135   // down event on the render widget and use it as the timestamp of the
136   // activation event to show the context menu.
137   content::RenderWidgetHostView* view = NULL;
138   if (params.custom_context.render_widget_id !=
139       content::CustomContextMenuContext::kCurrentRenderWidget) {
140     content::RenderWidgetHost* host = content::RenderWidgetHost::FromID(
141         web_contents_->GetRenderProcessHost()->GetID(),
142         params.custom_context.render_widget_id);
143     if (!host) {
144       NOTREACHED();
145       return;
146     }
147     view = host->GetView();
148   } else {
149     view = web_contents_->GetRenderWidgetHostView();
150   }
151
152   context_menu_.reset(
153       new RenderViewContextMenuGtk(render_frame_host, params, view));
154   context_menu_->Init();
155
156   // Don't show empty menus.
157   if (context_menu_->menu_model().GetItemCount() == 0)
158     return;
159
160   gfx::Rect bounds;
161   web_contents_->GetView()->GetContainerBounds(&bounds);
162   gfx::Point point = bounds.origin();
163   point.Offset(params.x, params.y);
164   context_menu_->Popup(point);
165 }
166
167 content::WebDragDestDelegate*
168     ChromeWebContentsViewDelegateGtk::GetDragDestDelegate() {
169   return bookmark_handler_gtk_.get();
170 }
171
172 void ChromeWebContentsViewDelegateGtk::OnSetFloatingPosition(
173     GtkWidget* floating_container, GtkAllocation* allocation) {
174   if (!web_contents_modal_dialog_)
175     return;
176
177   // Place each web contents modal dialog in the center of the view.
178   GtkWidget* widget = web_contents_modal_dialog_;
179   DCHECK(gtk_widget_get_parent(widget) == floating_.get());
180
181   GtkRequisition requisition;
182   gtk_widget_size_request(widget, &requisition);
183
184   GValue value = { 0, };
185   g_value_init(&value, G_TYPE_INT);
186
187   int child_x = std::max((allocation->width - requisition.width) / 2, 0);
188   g_value_set_int(&value, child_x);
189   gtk_container_child_set_property(GTK_CONTAINER(floating_container),
190                                    widget, "x", &value);
191
192   int child_y = std::max((allocation->height - requisition.height) / 2, 0);
193   g_value_set_int(&value, child_y);
194   gtk_container_child_set_property(GTK_CONTAINER(floating_container),
195                                    widget, "y", &value);
196   g_value_unset(&value);
197 }
198
199 namespace chrome {
200
201 content::WebContentsViewDelegate* CreateWebContentsViewDelegate(
202     content::WebContents* web_contents) {
203   return new ChromeWebContentsViewDelegateGtk(web_contents);
204 }
205
206 }  // namespace chrome