Index: views/controls/native/native_view_host_gtk.cc |
diff --git a/views/controls/native/native_view_host_gtk.cc b/views/controls/native/native_view_host_gtk.cc |
index 50255f916e604dbe4401b9e1d460155c4fe99233..3284344db56fb6437bf8ee296f7646e283270e75 100644 |
--- a/views/controls/native/native_view_host_gtk.cc |
+++ b/views/controls/native/native_view_host_gtk.cc |
@@ -85,6 +85,16 @@ void UnblockFocusSignals(GtkWidget* widget, gpointer data) { |
gtk_container_foreach(GTK_CONTAINER(widget), UnblockFocusSignals, data); |
} |
+// Removes |child| from |parent|. |
+void RemoveFromParent(GtkWidget* child, gpointer parent) { |
+ gtk_container_remove(GTK_CONTAINER(parent), child); |
+} |
+ |
+// Reparents |child| to be a child of |parent|. |
+void Reparent(GtkWidget* child, gpointer parent) { |
+ gtk_widget_reparent(child, GTK_WIDGET(parent)); |
+} |
+ |
} // namespace |
//////////////////////////////////////////////////////////////////////////////// |
@@ -100,31 +110,31 @@ NativeViewHostGtk::NativeViewHostGtk(NativeViewHost* host) |
} |
NativeViewHostGtk::~NativeViewHostGtk() { |
- if (fixed_) |
+ if (fixed_) { |
+ gtk_container_foreach(GTK_CONTAINER(fixed_), RemoveFromParent, fixed_); |
gtk_widget_destroy(fixed_); |
+ } |
} |
//////////////////////////////////////////////////////////////////////////////// |
// NativeViewHostGtk, NativeViewHostWrapper implementation: |
void NativeViewHostGtk::NativeViewAttached() { |
- DCHECK(host_->native_view()); |
- if (gtk_widget_get_parent(host_->native_view())) |
- gtk_widget_reparent(host_->native_view(), fixed_); |
- else |
- gtk_container_add(GTK_CONTAINER(fixed_), host_->native_view()); |
+ AttachHostWidget(); |
+ |
+ GtkWidget* host_widget = host_->native_view(); |
// Let the widget know that the native component has been painted. |
- views::NativeWidgetGtk::RegisterChildExposeHandler(host_->native_view()); |
+ views::NativeWidgetGtk::RegisterChildExposeHandler(host_widget); |
if (!destroy_signal_id_) { |
- destroy_signal_id_ = g_signal_connect(host_->native_view(), |
+ destroy_signal_id_ = g_signal_connect(host_widget, |
"destroy", G_CALLBACK(CallDestroy), |
this); |
} |
if (!focus_signal_id_) { |
- focus_signal_id_ = g_signal_connect(host_->native_view(), |
+ focus_signal_id_ = g_signal_connect(host_widget, |
"focus-in-event", |
G_CALLBACK(CallFocusIn), this); |
} |
@@ -132,35 +142,20 @@ void NativeViewHostGtk::NativeViewAttached() { |
// Always layout though. |
host_->Layout(); |
- // We own the native view as long as it's attached, so that we can safely |
- // reparent it in multiple passes. |
- gtk_widget_ref(host_->native_view()); |
- |
// TODO(port): figure out focus. |
} |
void NativeViewHostGtk::NativeViewDetaching(bool destroyed) { |
- DCHECK(host_->native_view()); |
+ GtkWidget* host_widget = host_->native_view(); |
+ DCHECK(host_widget); |
- g_signal_handler_disconnect(G_OBJECT(host_->native_view()), |
- destroy_signal_id_); |
+ g_signal_handler_disconnect(G_OBJECT(host_widget), destroy_signal_id_); |
destroy_signal_id_ = 0; |
- g_signal_handler_disconnect(G_OBJECT(host_->native_view()), |
- focus_signal_id_); |
+ g_signal_handler_disconnect(G_OBJECT(host_widget), focus_signal_id_); |
focus_signal_id_ = 0; |
installed_clip_ = false; |
- |
- if (fixed_ && !destroyed) { |
- DCHECK_NE(static_cast<gfx::NativeView>(NULL), |
- gtk_widget_get_parent(host_->native_view())); |
- gtk_container_remove(GTK_CONTAINER(fixed_), host_->native_view()); |
- DCHECK_EQ( |
- 0U, g_list_length(gtk_container_get_children(GTK_CONTAINER(fixed_)))); |
- } |
- |
- g_object_unref(G_OBJECT(host_->native_view())); |
} |
void NativeViewHostGtk::AddedToWidget() { |
@@ -174,15 +169,14 @@ void NativeViewHostGtk::AddedToWidget() { |
if (!host_->native_view()) |
return; |
- if (gtk_widget_get_parent(host_->native_view())) |
- gtk_widget_reparent(host_->native_view(), fixed_); |
- else |
- gtk_container_add(GTK_CONTAINER(fixed_), host_->native_view()); |
+ AttachHostWidget(); |
- if (host_->IsVisibleInRootView()) |
+ if (host_->IsVisibleInRootView()) { |
+ gtk_widget_show(host_->native_view()); |
gtk_widget_show(fixed_); |
- else |
+ } else { |
gtk_widget_hide(fixed_); |
+ } |
host_->Layout(); |
} |
@@ -235,18 +229,19 @@ void NativeViewHostGtk::ShowWidget(int x, int y, int w, int h) { |
fixed_h = std::min(installed_clip_bounds_.height(), h); |
} |
+ GtkWidget* host_widget = host_->native_view(); |
// Don't call gtk_widget_size_allocate now, as we're possibly in the |
// middle of a re-size, and it kicks off another re-size, and you |
// get flashing. Instead, we'll set the desired size as properties |
// on the widget and queue the re-size. |
- gtk_views_fixed_set_widget_size(host_->native_view(), child_w, child_h); |
- gtk_fixed_move(GTK_FIXED(fixed_), host_->native_view(), child_x, child_y); |
+ gtk_views_fixed_set_widget_size(host_widget, child_w, child_h); |
+ gtk_fixed_move(GTK_FIXED(fixed_), host_widget, child_x, child_y); |
// Size and place the fixed_. |
GetHostWidget()->PositionChild(fixed_, fixed_x, fixed_y, fixed_w, fixed_h); |
+ gtk_widget_show(host_widget); |
gtk_widget_show(fixed_); |
- gtk_widget_show(host_->native_view()); |
} |
void NativeViewHostGtk::HideWidget() { |
@@ -255,8 +250,9 @@ void NativeViewHostGtk::HideWidget() { |
} |
void NativeViewHostGtk::SetFocus() { |
- DCHECK(host_->native_view()); |
- gtk_widget_grab_focus(host_->native_view()); |
+ GtkWidget* host_widget = host_->native_view(); |
+ DCHECK(host_widget); |
+ gtk_widget_grab_focus(host_widget); |
} |
gfx::NativeViewAccessible NativeViewHostGtk::GetNativeViewAccessible() { |
@@ -285,24 +281,34 @@ void NativeViewHostGtk::CreateFixed(bool needs_window) { |
gtk_widget_grab_focus(GetHostWidget()->GetNativeView()); |
} |
- DestroyFixed(); |
+ // Move all the contained widgets to the new fixed. |
+ GtkWidget* new_fixed = gtk_views_fixed_new(); |
+ if (fixed_) { |
+ gtk_container_foreach(GTK_CONTAINER(fixed_), Reparent, new_fixed); |
+ DestroyFixed(); |
+ } |
+ fixed_ = new_fixed; |
- fixed_ = gtk_views_fixed_new(); |
gtk_widget_set_name(fixed_, "views-native-view-host-fixed"); |
gtk_fixed_set_has_window(GTK_FIXED(fixed_), needs_window); |
+ |
// Defeat refcounting. We need to own the fixed. |
gtk_widget_ref(fixed_); |
NativeWidgetGtk* widget_gtk = GetHostWidget(); |
- if (widget_gtk) |
+ if (widget_gtk) { |
widget_gtk->AddChild(fixed_); |
+ // Clear the background so we don't get flicker. |
+ gtk_widget_realize(fixed_); |
+ gdk_window_set_back_pixmap(fixed_->window, NULL, false); |
+ } |
if (host_->native_view()) |
- gtk_container_add(GTK_CONTAINER(fixed_), host_->native_view()); |
+ AttachHostWidget(); |
- if (widget_gtk && host_->native_view() && focused_widget) { |
+ if (widget_gtk && host_->native_view() && focused_widget) |
gtk_widget_grab_focus(focused_widget); |
- } |
+ |
if (focus_event_blocked) { |
// Unblocking a signal handler that is not blocked fails. |
// Unblock only when it's unblocked. |
@@ -315,13 +321,9 @@ void NativeViewHostGtk::DestroyFixed() { |
return; |
gtk_widget_hide(fixed_); |
+ gtk_container_foreach(GTK_CONTAINER(fixed_), RemoveFromParent, fixed_); |
GetHostWidget()->RemoveChild(fixed_); |
- if (host_->native_view()) { |
- // We can safely remove the widget from its container since we own the |
- // widget from the moment it is attached. |
- gtk_container_remove(GTK_CONTAINER(fixed_), host_->native_view()); |
- } |
// fixed_ should not have any children this point. |
DCHECK_EQ(0U, |
g_list_length(gtk_container_get_children(GTK_CONTAINER(fixed_)))); |
@@ -349,6 +351,30 @@ GtkWidget* NativeViewHostGtk::GetFocusedDescendant() { |
focused : NULL; |
} |
+void NativeViewHostGtk::AttachHostWidget() { |
+ GtkWidget* host_widget = host_->native_view(); |
+ DCHECK(host_widget); |
+ |
+ GtkWidget* host_parent = gtk_widget_get_parent(host_widget); |
+ bool parent_changed = true; |
+ if (host_parent) { |
+ if (host_parent != fixed_) |
+ gtk_widget_reparent(host_widget, fixed_); |
+ else |
+ parent_changed = false; |
+ } else { |
+ gtk_container_add(GTK_CONTAINER(fixed_), host_widget); |
+ } |
+ |
+ if (parent_changed) { |
+ // We need to clear the background so we don't get flicker on tab switching. |
+ // To do that we must realize the widget if it's not already. |
+ if (!GTK_WIDGET_REALIZED(host_widget)) |
+ gtk_widget_realize(host_widget); |
+ gdk_window_set_back_pixmap(host_widget->window, NULL, false); |
+ } |
+} |
+ |
// static |
void NativeViewHostGtk::CallDestroy(GtkObject* object, |
NativeViewHostGtk* host) { |