| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "chrome/browser/ui/gtk/tab_contents_container_gtk.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 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" | |
| 17 | |
| 18 namespace { | |
| 19 void HideWidget(GtkWidget* widget, gpointer ignored) { | |
| 20 gtk_widget_hide(widget); | |
| 21 } | |
| 22 } // namespace | |
| 23 | |
| 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: | |
| 30 // | |
| 31 // +- GtkFloatingContainer |floating_| -------------------------------+ | |
| 32 // |+- GtkExpandedContainer |expanded_| -----------------------------+| | |
| 33 // || || | |
| 34 // || || | |
| 35 // || || | |
| 36 // || || | |
| 37 // |+- (StatusBubble) ------+ || | |
| 38 // |+ + || | |
| 39 // |+-----------------------+----------------------------------------+| | |
| 40 // +------------------------------------------------------------------+ | |
| 41 | |
| 42 floating_.Own(gtk_floating_container_new()); | |
| 43 gtk_widget_set_name(floating_.get(), "chrome-tab-contents-container"); | |
| 44 | |
| 45 expanded_ = gtk_expanded_container_new(); | |
| 46 gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_); | |
| 47 | |
| 48 if (status_bubble_) { | |
| 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); | |
| 53 } | |
| 54 | |
| 55 gtk_widget_show(expanded_); | |
| 56 gtk_widget_show(floating_.get()); | |
| 57 | |
| 58 ViewIDUtil::SetDelegateForWidget(widget(), this); | |
| 59 } | |
| 60 | |
| 61 TabContentsContainerGtk::~TabContentsContainerGtk() { | |
| 62 floating_.Destroy(); | |
| 63 } | |
| 64 | |
| 65 void TabContentsContainerGtk::SetTab(content::WebContents* tab) { | |
| 66 if (tab == web_contents()) | |
| 67 return; | |
| 68 | |
| 69 HideTab(); | |
| 70 WebContentsObserver::Observe(tab); | |
| 71 is_embedding_fullscreen_widget_ = | |
| 72 should_embed_fullscreen_widgets_ && | |
| 73 tab && tab->GetFullscreenRenderWidgetHostView(); | |
| 74 PackTab(); | |
| 75 } | |
| 76 | |
| 77 void TabContentsContainerGtk::PackTab() { | |
| 78 content::WebContents* const tab = web_contents(); | |
| 79 if (!tab) | |
| 80 return; | |
| 81 | |
| 82 const gfx::NativeView widget = is_embedding_fullscreen_widget_ ? | |
| 83 tab->GetFullscreenRenderWidgetHostView()->GetNativeView() : | |
| 84 tab->GetView()->GetNativeView(); | |
| 85 if (widget) { | |
| 86 if (gtk_widget_get_parent(widget) != expanded_) | |
| 87 gtk_container_add(GTK_CONTAINER(expanded_), widget); | |
| 88 gtk_widget_show(widget); | |
| 89 } | |
| 90 | |
| 91 if (is_embedding_fullscreen_widget_) | |
| 92 return; | |
| 93 | |
| 94 tab->WasShown(); | |
| 95 | |
| 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(); | |
| 99 if (content_widget) { | |
| 100 GdkWindow* const content_gdk_window = gtk_widget_get_window(content_widget); | |
| 101 if (content_gdk_window) | |
| 102 gdk_window_lower(content_gdk_window); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 void TabContentsContainerGtk::HideTab() { | |
| 107 content::WebContents* const tab = web_contents(); | |
| 108 if (!tab) | |
| 109 return; | |
| 110 | |
| 111 gtk_container_foreach(GTK_CONTAINER(expanded_), &HideWidget, NULL); | |
| 112 if (is_embedding_fullscreen_widget_) | |
| 113 return; | |
| 114 tab->WasHidden(); | |
| 115 } | |
| 116 | |
| 117 void TabContentsContainerGtk::DetachTab(content::WebContents* tab) { | |
| 118 if (!tab) | |
| 119 return; | |
| 120 if (tab == web_contents()) { | |
| 121 HideTab(); | |
| 122 WebContentsObserver::Observe(NULL); | |
| 123 } | |
| 124 | |
| 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; | |
| 130 | |
| 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. | |
| 133 if (widget) { | |
| 134 GtkWidget* const parent = gtk_widget_get_parent(widget); | |
| 135 if (parent) { | |
| 136 DCHECK_EQ(parent, expanded_); | |
| 137 gtk_container_remove(GTK_CONTAINER(expanded_), widget); | |
| 138 } | |
| 139 } | |
| 140 if (fs_widget) { | |
| 141 GtkWidget* const parent = gtk_widget_get_parent(fs_widget); | |
| 142 if (parent) { | |
| 143 DCHECK_EQ(parent, expanded_); | |
| 144 gtk_container_remove(GTK_CONTAINER(expanded_), fs_widget); | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 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. | |
| 153 DetachTab(contents); | |
| 154 } | |
| 155 | |
| 156 // ----------------------------------------------------------------------------- | |
| 157 // ViewIDUtil::Delegate implementation | |
| 158 | |
| 159 GtkWidget* TabContentsContainerGtk::GetWidgetForViewID(ViewID view_id) { | |
| 160 if (view_id == VIEW_ID_TAB_CONTAINER) | |
| 161 return widget(); | |
| 162 | |
| 163 return NULL; | |
| 164 } | |
| 165 | |
| 166 // ----------------------------------------------------------------------------- | |
| 167 | |
| 168 void TabContentsContainerGtk::DidShowFullscreenWidget(int routing_id) { | |
| 169 if (!should_embed_fullscreen_widgets_) | |
| 170 return; | |
| 171 HideTab(); | |
| 172 is_embedding_fullscreen_widget_ = | |
| 173 web_contents() && web_contents()->GetFullscreenRenderWidgetHostView(); | |
| 174 PackTab(); | |
| 175 } | |
| 176 | |
| 177 void TabContentsContainerGtk::DidDestroyFullscreenWidget(int routing_id) { | |
| 178 if (!should_embed_fullscreen_widgets_) | |
| 179 return; | |
| 180 HideTab(); | |
| 181 is_embedding_fullscreen_widget_ = false; | |
| 182 PackTab(); | |
| 183 } | |
| 184 | |
| 185 // static | |
| 186 void TabContentsContainerGtk::OnSetFloatingPosition( | |
| 187 GtkFloatingContainer* floating_container, GtkAllocation* allocation, | |
| 188 TabContentsContainerGtk* tab_contents_container) { | |
| 189 StatusBubbleGtk* status = tab_contents_container->status_bubble_; | |
| 190 | |
| 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); | |
| 195 | |
| 196 bool ltr = !base::i18n::IsRTL(); | |
| 197 | |
| 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); | |
| 202 else | |
| 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); | |
| 206 | |
| 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); | |
| 212 } | |
| OLD | NEW |