diff options
author | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-25 20:50:32 +0000 |
---|---|---|
committer | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-25 20:50:32 +0000 |
commit | c0478b0985b9893601125a88a32a648656a75948 (patch) | |
tree | 8af9f0dcb303cbcdbf0da4c134f025d4e7ddd238 /webkit/glue/plugins | |
parent | d4eb7120deddccf96ff85ecc393b0757497bb7d6 (diff) | |
download | chromium_src-c0478b0985b9893601125a88a32a648656a75948.zip chromium_src-c0478b0985b9893601125a88a32a648656a75948.tar.gz chromium_src-c0478b0985b9893601125a88a32a648656a75948.tar.bz2 |
linux: new socket/plug code for windowed plugins
This CL reworks the GtkSocket/GtkPlug code for windowed plugins on linux. Instead of having the plugin ask the browser to create a socket to plug into, it simply creates a plug and sends it to the browser. The browser creates a socket and attaches the plug when the socket becomes realized
This fixes 2 main issues:
- we can create windowed plugins in background tabs (Issue 16125)
- we can detach tabs with windowed plugins and reattach them (Issue 17110)
I reworked the IPCs, so it removes some amount of linux-specific things. We also need less synchronous IPCs to create/destroy plugins, so that should be a bit faster. In particular, I removed the plugin pid map, and instead made sure the renderer always destroys the plugin containers if the plugin process crashes - they will be destroyed if the renderer process crashes. Let me know if you have an issue with that.
Also, the intermediate plug/socket creation now happens in webplugin_delegate_impl_gtk. That means test_shell uses it as well. It made the code a lot simpler, and means we're testing it as well, albeit with a bit of extra overhead.
Bonus: I found a big bad bug in the GtkPluginContainer that made its width/height alias with some internal gtk structures. That was certainly causing some amounts of bugs.
Bonus 2: scrolling now looks more in sync with the rest of the page, though I'm not exactly sure which part caused that.
BUG=16125,17110
TEST=a lot of manual testing involving YouTube videos
Review URL: http://codereview.chromium.org/174295
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24309 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/plugins')
-rw-r--r-- | webkit/glue/plugins/gtk_plugin_container.cc | 2 | ||||
-rw-r--r-- | webkit/glue/plugins/gtk_plugin_container_manager.cc | 105 | ||||
-rw-r--r-- | webkit/glue/plugins/gtk_plugin_container_manager.h | 21 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 7 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_gtk.cc | 35 |
5 files changed, 102 insertions, 68 deletions
diff --git a/webkit/glue/plugins/gtk_plugin_container.cc b/webkit/glue/plugins/gtk_plugin_container.cc index c487fa0..c80bbf1 100644 --- a/webkit/glue/plugins/gtk_plugin_container.cc +++ b/webkit/glue/plugins/gtk_plugin_container.cc @@ -35,7 +35,7 @@ class GtkPluginContainer : public GtkSocket { NULL, NULL, static_cast<GClassInitFunc>(&ClassInit), NULL, NULL, - sizeof(GtkSocket), // We are identical to a GtkSocket. + sizeof(GtkPluginContainer), 0, &InstanceInit, }; type = g_type_register_static(GTK_TYPE_SOCKET, diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.cc b/webkit/glue/plugins/gtk_plugin_container_manager.cc index 266687b..4683e08 100644 --- a/webkit/glue/plugins/gtk_plugin_container_manager.cc +++ b/webkit/glue/plugins/gtk_plugin_container_manager.cc @@ -11,54 +11,44 @@ #include "webkit/glue/plugins/gtk_plugin_container.h" #include "webkit/glue/webplugin.h" -// Helper function that always returns true. Used to prevent Gtk from -// destroying our socket when the plug goes away: we manage it ourselves. -static gboolean AlwaysTrue(void* unused) { - return TRUE; -} - -gfx::PluginWindowHandle GtkPluginContainerManager::CreatePluginContainer() { +GtkWidget* GtkPluginContainerManager::CreatePluginContainer( + gfx::PluginWindowHandle id) { DCHECK(host_widget_); - // If the current view hasn't been attached to a top-level window (e.g. it is - // loaded in a background tab), it can't be realized without asserting in - // Gtk, so we can't get the XID for the socket. Instead, don't create one. - // We'll never see the plugin but it's better than crashing. - // TODO(piman@google.com): figure out how to add the background tab to the - // widget hierarchy, so that it can be realized. It doesn't have to be - // visible. - if (!gtk_widget_get_ancestor(host_widget_, GTK_TYPE_WINDOW)) { - NOTIMPLEMENTED() << "Can't create plugins in background tabs."; - return 0; - } - - GtkWidget* plugin_container = gtk_plugin_container_new(); - g_signal_connect(G_OBJECT(plugin_container), "plug-removed", - G_CALLBACK(AlwaysTrue), NULL); - // Add a connection to the "unrealize" signal so that if the parent widget - // gets destroyed before the DestroyPluginContainer gets called, bad things - // don't happen. - g_signal_connect(G_OBJECT(plugin_container), "unrealize", - G_CALLBACK(UnrealizeCallback), this); - gtk_container_add(GTK_CONTAINER(host_widget_), plugin_container); - gtk_widget_show(plugin_container); - gtk_widget_realize(plugin_container); - - gfx::PluginWindowHandle id = gtk_socket_get_id(GTK_SOCKET(plugin_container)); - - plugin_window_to_widget_map_.insert(std::make_pair(id, plugin_container)); - - return id; + GtkWidget *widget = gtk_plugin_container_new(); + plugin_window_to_widget_map_.insert(std::make_pair(id, widget)); + + // The Realize callback is responsible for adding the plug into the socket. + // The reason is 2-fold: + // - the plug can't be added until the socket is realized, but this may not + // happen until the socket is attached to a top-level window, which isn't the + // case for background tabs. + // - when dragging tabs, the socket gets unrealized, which breaks the XEMBED + // connection. We need to make it again when the tab is reattached, and the + // socket gets realized again. + // + // Note, the RealizeCallback relies on the plugin_window_to_widget_map_ to + // have the mapping. + g_signal_connect(G_OBJECT(widget), "realize", + G_CALLBACK(RealizeCallback), this); + + // Don't destroy the widget when the plug is removed. + g_signal_connect(G_OBJECT(widget), "plug-removed", + G_CALLBACK(gtk_true), NULL); + + gtk_container_add(GTK_CONTAINER(host_widget_), widget); + gtk_widget_show(widget); + + return widget; } void GtkPluginContainerManager::DestroyPluginContainer( - gfx::PluginWindowHandle container) { - GtkWidget* plugin_container = MapIDToWidget(container); - if (!plugin_container) - return; + gfx::PluginWindowHandle id) { + DCHECK(host_widget_); + GtkWidget* widget = MapIDToWidget(id); + if (widget) + gtk_widget_destroy(widget); - // This will call the UnrealizeCallback that will remove plugin_container - // from the map. - gtk_widget_destroy(plugin_container); + plugin_window_to_widget_map_.erase(id); } void GtkPluginContainerManager::MovePluginContainer( @@ -117,7 +107,8 @@ void GtkPluginContainerManager::MovePluginContainer( move.window_rect.height()); } -GtkWidget* GtkPluginContainerManager::MapIDToWidget(gfx::PluginWindowHandle id) { +GtkWidget* GtkPluginContainerManager::MapIDToWidget( + gfx::PluginWindowHandle id) { PluginWindowToWidgetMap::const_iterator i = plugin_window_to_widget_map_.find(id); if (i != plugin_window_to_widget_map_.end()) @@ -128,12 +119,26 @@ GtkWidget* GtkPluginContainerManager::MapIDToWidget(gfx::PluginWindowHandle id) return NULL; } -void GtkPluginContainerManager::UnrealizeCallback(GtkWidget* widget, - void* user_data) { - // This is the last chance to get the XID for the widget. Remove it from the - // map here. +gfx::PluginWindowHandle GtkPluginContainerManager::MapWidgetToID( + GtkWidget* widget) { + for (PluginWindowToWidgetMap::const_iterator i = + plugin_window_to_widget_map_.begin(); + i != plugin_window_to_widget_map_.end(); ++i) { + if (i->second == widget) + return i->first; + } + + LOG(ERROR) << "Request for id for unknown widget"; + return 0; +} + +// static +void GtkPluginContainerManager::RealizeCallback(GtkWidget* widget, + void* user_data) { GtkPluginContainerManager* plugin_container_manager = static_cast<GtkPluginContainerManager*>(user_data); - gfx::PluginWindowHandle id = gtk_socket_get_id(GTK_SOCKET(widget)); - plugin_container_manager->plugin_window_to_widget_map_.erase(id); + + gfx::PluginWindowHandle id = plugin_container_manager->MapWidgetToID(widget); + if (id) + gtk_socket_add_id(GTK_SOCKET(widget), id); } diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.h b/webkit/glue/plugins/gtk_plugin_container_manager.h index 648e963..30a6b1a 100644 --- a/webkit/glue/plugins/gtk_plugin_container_manager.h +++ b/webkit/glue/plugins/gtk_plugin_container_manager.h @@ -21,28 +21,31 @@ class GtkPluginContainerManager { // Sets the widget that will host the plugin containers. Must be a GtkFixed. void set_host_widget(GtkWidget *widget) { host_widget_ = widget; } - // Creates a new plugin container, returning its XID. - gfx::PluginWindowHandle CreatePluginContainer(); + // Creates a new plugin container, for a given plugin XID. + GtkWidget* CreatePluginContainer(gfx::PluginWindowHandle id); - // Destroys a plugin container, given its XID. - void DestroyPluginContainer(gfx::PluginWindowHandle container); + // Destroys a plugin container, given the plugin XID. + void DestroyPluginContainer(gfx::PluginWindowHandle id); // Takes an update from WebKit about a plugin's position and side and moves // the plugin accordingly. void MovePluginContainer(const WebPluginGeometry& move); private: - // Maps a plugin container XID to the corresponding widget. + // Maps a plugin XID to the corresponding container widget. GtkWidget* MapIDToWidget(gfx::PluginWindowHandle id); - // Callback for when the plugin container loses its XID, so that it can be - // removed from plugin_window_to_widget_map_. - static void UnrealizeCallback(GtkWidget *widget, void *user_data); + // Maps a container widget to the corresponding plugin XID. + gfx::PluginWindowHandle MapWidgetToID(GtkWidget* widget); + + // Callback for when the plugin container gets realized, at which point it + // plugs the plugin XID. + static void RealizeCallback(GtkWidget *widget, void *user_data); // Parent of the plugin containers. GtkWidget* host_widget_; - // A map that associates plugin containers to their XID. + // A map that associates plugin containers to the plugin XID. typedef std::map<gfx::PluginWindowHandle, GtkWidget*> PluginWindowToWidgetMap; PluginWindowToWidgetMap plugin_window_to_widget_map_; }; diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index 106a040..90d8203 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -196,6 +196,13 @@ class WebPluginDelegateImpl : public WebPluginDelegate { GdkPixmap* pixmap_; double first_event_time_; + // On Linux some plugins assume that the GtkSocket container is in the same + // process. So we create a GtkPlug to plug into the browser's container, and + // a GtkSocket to hold the plugin. We then send the GtkPlug to the browser + // process. + GtkWidget* plug_; + GtkWidget* socket_; + // Ensure pixmap_ exists and is at least width by height pixels. void EnsurePixmapAtLeastSize(int width, int height); #endif diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc index da236b4..83d348b 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc @@ -68,6 +68,8 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( instance_(instance), pixmap_(NULL), first_event_time_(-1.0), + plug_(NULL), + socket_(NULL), parent_(containing_view), quirks_(0) { memset(&window_, 0, sizeof(window_)); @@ -134,8 +136,10 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url, if (!WindowedCreatePlugin()) return false; } + gfx::PluginWindowHandle handle = + windowless_ ? 0 : gtk_plug_get_id(GTK_PLUG(plug_)); + plugin->SetWindow(handle); - plugin->SetWindow(windowed_handle_); plugin_url_ = url.spec(); return true; @@ -258,6 +262,7 @@ void WebPluginDelegateImpl::WindowedUpdateGeometry( bool WebPluginDelegateImpl::WindowedCreatePlugin() { DCHECK(!windowed_handle_); + DCHECK(!plug_); bool xembed; NPError err = instance_->NPP_GetValue(NPPVpluginNeedsXEmbed, &xembed); @@ -267,11 +272,22 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() { return false; } - // Xembed plugins need a window created for them browser-side. - // Do that now. - windowed_handle_ = plugin_->CreatePluginContainer(); - if (!windowed_handle_) - return false; + // Passing 0 as the socket XID creates a plug without plugging it in a socket + // yet, so that it can be latter added with gtk_socket_add_id(). + plug_ = gtk_plug_new(0); + gtk_widget_show(plug_); + socket_ = gtk_socket_new(); + gtk_widget_show(socket_); + gtk_container_add(GTK_CONTAINER(plug_), socket_); + gtk_widget_show_all(plug_); + + // Prevent the plug from being destroyed if the browser kills the container + // window. + g_signal_connect(plug_, "delete-event", G_CALLBACK(gtk_true), NULL); + // Prevent the socket from being destroyed when the plugin removes itself. + g_signal_connect(socket_, "plug_removed", G_CALLBACK(gtk_true), NULL); + + windowed_handle_ = gtk_socket_get_id(GTK_SOCKET(socket_)); window_.window = reinterpret_cast<void*>(windowed_handle_); @@ -288,9 +304,12 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() { } void WebPluginDelegateImpl::WindowedDestroyWindow() { - if (windowed_handle_) { - plugin_->WillDestroyWindow(windowed_handle_); + if (plug_) { + plugin_->WillDestroyWindow(gtk_plug_get_id(GTK_PLUG(plug_))); + gtk_widget_destroy(plug_); + plug_ = NULL; + socket_ = NULL; windowed_handle_ = 0; } } |