1 // Copyright 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.
5 #include "chrome/browser/ui/gtk/tab_contents_container_gtk.h"
9 #include "base/i18n/rtl.h"
10 #include "chrome/browser/ui/gtk/status_bubble_gtk.h"
11 #include "content/public/browser/render_widget_host_view.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/browser/web_contents_view.h"
14 #include "ui/base/gtk/gtk_expanded_container.h"
15 #include "ui/base/gtk/gtk_floating_container.h"
16 #include "ui/gfx/native_widget_types.h"
19 void HideWidget(GtkWidget
* widget
, gpointer ignored
) {
20 gtk_widget_hide(widget
);
24 TabContentsContainerGtk::TabContentsContainerGtk(StatusBubbleGtk
* status_bubble
,
25 bool embed_fullscreen_widget
)
26 : status_bubble_(status_bubble
),
27 should_embed_fullscreen_widgets_(embed_fullscreen_widget
),
28 is_embedding_fullscreen_widget_(false) {
29 // A high level overview of the TabContentsContainer:
31 // +- GtkFloatingContainer |floating_| -------------------------------+
32 // |+- GtkExpandedContainer |expanded_| -----------------------------+|
37 // |+- (StatusBubble) ------+ ||
39 // |+-----------------------+----------------------------------------+|
40 // +------------------------------------------------------------------+
42 floating_
.Own(gtk_floating_container_new());
43 gtk_widget_set_name(floating_
.get(), "chrome-tab-contents-container");
45 expanded_
= gtk_expanded_container_new();
46 gtk_container_add(GTK_CONTAINER(floating_
.get()), expanded_
);
49 gtk_floating_container_add_floating(GTK_FLOATING_CONTAINER(floating_
.get()),
50 status_bubble_
->widget());
51 g_signal_connect(floating_
.get(), "set-floating-position",
52 G_CALLBACK(OnSetFloatingPosition
), this);
55 gtk_widget_show(expanded_
);
56 gtk_widget_show(floating_
.get());
58 ViewIDUtil::SetDelegateForWidget(widget(), this);
61 TabContentsContainerGtk::~TabContentsContainerGtk() {
65 void TabContentsContainerGtk::SetTab(content::WebContents
* tab
) {
66 if (tab
== web_contents())
70 WebContentsObserver::Observe(tab
);
71 is_embedding_fullscreen_widget_
=
72 should_embed_fullscreen_widgets_
&&
73 tab
&& tab
->GetFullscreenRenderWidgetHostView();
77 void TabContentsContainerGtk::PackTab() {
78 content::WebContents
* const tab
= web_contents();
82 const gfx::NativeView widget
= is_embedding_fullscreen_widget_
?
83 tab
->GetFullscreenRenderWidgetHostView()->GetNativeView() :
84 tab
->GetView()->GetNativeView();
86 if (gtk_widget_get_parent(widget
) != expanded_
)
87 gtk_container_add(GTK_CONTAINER(expanded_
), widget
);
88 gtk_widget_show(widget
);
91 if (is_embedding_fullscreen_widget_
)
96 // Make sure that the tab is below the find bar. Sometimes the content
97 // native view will be null.
98 GtkWidget
* const content_widget
= tab
->GetView()->GetContentNativeView();
100 GdkWindow
* const content_gdk_window
= gtk_widget_get_window(content_widget
);
101 if (content_gdk_window
)
102 gdk_window_lower(content_gdk_window
);
106 void TabContentsContainerGtk::HideTab() {
107 content::WebContents
* const tab
= web_contents();
111 gtk_container_foreach(GTK_CONTAINER(expanded_
), &HideWidget
, NULL
);
112 if (is_embedding_fullscreen_widget_
)
117 void TabContentsContainerGtk::DetachTab(content::WebContents
* tab
) {
120 if (tab
== web_contents()) {
122 WebContentsObserver::Observe(NULL
);
125 const gfx::NativeView widget
= tab
->GetView()->GetNativeView();
126 const gfx::NativeView fs_widget
=
127 (should_embed_fullscreen_widgets_
&&
128 tab
->GetFullscreenRenderWidgetHostView()) ?
129 tab
->GetFullscreenRenderWidgetHostView()->GetNativeView() : NULL
;
131 // It is possible to detach an unrealized, unparented WebContents if you
132 // slow things down enough in valgrind. Might happen in the real world, too.
134 GtkWidget
* const parent
= gtk_widget_get_parent(widget
);
136 DCHECK_EQ(parent
, expanded_
);
137 gtk_container_remove(GTK_CONTAINER(expanded_
), widget
);
141 GtkWidget
* const parent
= gtk_widget_get_parent(fs_widget
);
143 DCHECK_EQ(parent
, expanded_
);
144 gtk_container_remove(GTK_CONTAINER(expanded_
), fs_widget
);
149 void TabContentsContainerGtk::WebContentsDestroyed(
150 content::WebContents
* contents
) {
151 // Sometimes, a WebContents is destroyed before we know about it. This allows
152 // us to clean up our state in case this happens.
156 // -----------------------------------------------------------------------------
157 // ViewIDUtil::Delegate implementation
159 GtkWidget
* TabContentsContainerGtk::GetWidgetForViewID(ViewID view_id
) {
160 if (view_id
== VIEW_ID_TAB_CONTAINER
)
166 // -----------------------------------------------------------------------------
168 void TabContentsContainerGtk::DidShowFullscreenWidget(int routing_id
) {
169 if (!should_embed_fullscreen_widgets_
)
172 is_embedding_fullscreen_widget_
=
173 web_contents() && web_contents()->GetFullscreenRenderWidgetHostView();
177 void TabContentsContainerGtk::DidDestroyFullscreenWidget(int routing_id
) {
178 if (!should_embed_fullscreen_widgets_
)
181 is_embedding_fullscreen_widget_
= false;
186 void TabContentsContainerGtk::OnSetFloatingPosition(
187 GtkFloatingContainer
* floating_container
, GtkAllocation
* allocation
,
188 TabContentsContainerGtk
* tab_contents_container
) {
189 StatusBubbleGtk
* status
= tab_contents_container
->status_bubble_
;
191 // Look at the size request of the status bubble and tell the
192 // GtkFloatingContainer where we want it positioned.
193 GtkRequisition requisition
;
194 gtk_widget_size_request(status
->widget(), &requisition
);
196 bool ltr
= !base::i18n::IsRTL();
198 GValue value
= { 0, };
199 g_value_init(&value
, G_TYPE_INT
);
200 if (ltr
^ status
->flip_horizontally()) // Is it on the left?
201 g_value_set_int(&value
, 0);
203 g_value_set_int(&value
, allocation
->width
- requisition
.width
);
204 gtk_container_child_set_property(GTK_CONTAINER(floating_container
),
205 status
->widget(), "x", &value
);
207 int child_y
= std::max(allocation
->height
- requisition
.height
, 0);
208 g_value_set_int(&value
, child_y
+ status
->y_offset());
209 gtk_container_child_set_property(GTK_CONTAINER(floating_container
),
210 status
->widget(), "y", &value
);
211 g_value_unset(&value
);