summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-25 20:50:32 +0000
committerpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-25 20:50:32 +0000
commitc0478b0985b9893601125a88a32a648656a75948 (patch)
tree8af9f0dcb303cbcdbf0da4c134f025d4e7ddd238 /webkit
parentd4eb7120deddccf96ff85ecc393b0757497bb7d6 (diff)
downloadchromium_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')
-rw-r--r--webkit/glue/plugins/gtk_plugin_container.cc2
-rw-r--r--webkit/glue/plugins/gtk_plugin_container_manager.cc105
-rw-r--r--webkit/glue/plugins/gtk_plugin_container_manager.h21
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h7
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_gtk.cc35
-rw-r--r--webkit/glue/webplugin.h10
-rw-r--r--webkit/glue/webplugin_impl.cc14
-rw-r--r--webkit/glue/webplugin_impl.h3
-rw-r--r--webkit/glue/webview_delegate.h6
-rw-r--r--webkit/tools/test_shell/test_webview_delegate.h4
-rw-r--r--webkit/tools/test_shell/test_webview_delegate_gtk.cc8
-rw-r--r--webkit/tools/test_shell/webview_host.h9
-rw-r--r--webkit/tools/test_shell/webview_host_gtk.cc6
13 files changed, 126 insertions, 104 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;
}
}
diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h
index d5f0cf6..886b031 100644
--- a/webkit/glue/webplugin.h
+++ b/webkit/glue/webplugin.h
@@ -25,7 +25,8 @@ struct NPObject;
// Describes the new location for a plugin window.
struct WebPluginGeometry {
// On Windows, this is the plugin window in the plugin process.
- // On X11, this is the browser process's hosting window (the GtkSocket).
+ // On X11, this is the XID of the plugin-side GtkPlug containing the
+ // GtkSocket hosting the actual plugin window.
gfx::PluginWindowHandle window;
gfx::Rect window_rect;
// Clip rect (include) and cutouts (excludes), relative to
@@ -51,13 +52,6 @@ class WebPlugin {
WebPlugin() { }
virtual ~WebPlugin() { }
-#if defined(OS_LINUX)
- // Called by the plugin delegate to request a container for a new
- // windowed plugin. This handle will later get destroyed with
- // WillDestroyWindow.
- virtual gfx::PluginWindowHandle CreatePluginContainer() = 0;
-#endif
-
// Called by the plugin delegate to let the WebPlugin know if the plugin is
// windowed (i.e. handle is not NULL) or windowless (handle is NULL). This
// tells the WebPlugin to send mouse/keyboard events to the plugin delegate,
diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc
index 3fe6b58..397fbd2 100644
--- a/webkit/glue/webplugin_impl.cc
+++ b/webkit/glue/webplugin_impl.cc
@@ -396,19 +396,17 @@ void WebPluginImpl::didFailLoading(const WebURLError& error) {
WebPluginImpl::~WebPluginImpl() {
}
-#if defined(OS_LINUX)
-gfx::PluginWindowHandle WebPluginImpl::CreatePluginContainer() {
- WebViewDelegate* view_delegate = GetWebViewDelegate();
- if (!view_delegate)
- return 0;
- return view_delegate->CreatePluginContainer();
-}
-#endif
void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) {
if (window) {
DCHECK(!windowless_); // Make sure not called twice.
window_ = window;
+ WebViewDelegate* view_delegate = GetWebViewDelegate();
+ if (view_delegate) {
+ // Tell the view delegate that the plugin window was created, so that it
+ // can create necessary container widgets.
+ view_delegate->CreatedPluginWindow(window);
+ }
} else {
DCHECK(!window_); // Make sure not called twice.
windowless_ = true;
diff --git a/webkit/glue/webplugin_impl.h b/webkit/glue/webplugin_impl.h
index fd83ba9..7f98759 100644
--- a/webkit/glue/webplugin_impl.h
+++ b/webkit/glue/webplugin_impl.h
@@ -100,9 +100,6 @@ class WebPluginImpl : public WebPlugin,
virtual void didFailLoading(const WebKit::WebURLError& error);
// WebPlugin implementation:
-#if defined(OS_LINUX)
- gfx::PluginWindowHandle CreatePluginContainer();
-#endif
void SetWindow(gfx::PluginWindowHandle window);
void WillDestroyWindow(gfx::PluginWindowHandle window);
#if defined(OS_WIN)
diff --git a/webkit/glue/webview_delegate.h b/webkit/glue/webview_delegate.h
index 826d1a7..6bf918c 100644
--- a/webkit/glue/webview_delegate.h
+++ b/webkit/glue/webview_delegate.h
@@ -149,9 +149,9 @@ class WebViewDelegate : virtual public WebKit::WebWidgetClient {
return NULL;
}
- // Called when a windowed plugin is initializing, to request a container
- // for the plugin. Only used on Linux.
- virtual gfx::PluginWindowHandle CreatePluginContainer() { return 0; }
+ // Called when a windowed plugin is created.
+ // Lets the view delegate create anything it is using to wrap the plugin.
+ virtual void CreatedPluginWindow(gfx::PluginWindowHandle handle) { }
// Called when a windowed plugin is closing.
// Lets the view delegate shut down anything it is using to wrap the plugin.
diff --git a/webkit/tools/test_shell/test_webview_delegate.h b/webkit/tools/test_shell/test_webview_delegate.h
index 6224b9c..971f199 100644
--- a/webkit/tools/test_shell/test_webview_delegate.h
+++ b/webkit/tools/test_shell/test_webview_delegate.h
@@ -77,8 +77,8 @@ class TestWebViewDelegate : public WebViewDelegate {
const std::string& clsid,
std::string* actual_mime_type);
#if defined(OS_LINUX)
- virtual gfx::PluginWindowHandle CreatePluginContainer();
- virtual void WillDestroyPluginWindow(gfx::PluginWindowHandle handle);
+ virtual void CreatedPluginWindow(gfx::PluginWindowHandle id);
+ virtual void WillDestroyPluginWindow(gfx::PluginWindowHandle id);
#endif
virtual WebKit::WebMediaPlayer* CreateWebMediaPlayer(
WebKit::WebMediaPlayerClient* client);
diff --git a/webkit/tools/test_shell/test_webview_delegate_gtk.cc b/webkit/tools/test_shell/test_webview_delegate_gtk.cc
index 460dceb..461d1d3 100644
--- a/webkit/tools/test_shell/test_webview_delegate_gtk.cc
+++ b/webkit/tools/test_shell/test_webview_delegate_gtk.cc
@@ -108,12 +108,12 @@ WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate(
return WebPluginDelegateImpl::Create(info.path, mtype, plugin_parent);
}
-gfx::PluginWindowHandle TestWebViewDelegate::CreatePluginContainer() {
- return shell_->webViewHost()->CreatePluginContainer();
+void TestWebViewDelegate::CreatedPluginWindow(gfx::PluginWindowHandle id) {
+ shell_->webViewHost()->CreatePluginContainer(id);
}
-void TestWebViewDelegate::WillDestroyPluginWindow(unsigned long id) {
- shell_->webViewHost()->OnPluginWindowDestroyed(id);
+void TestWebViewDelegate::WillDestroyPluginWindow(gfx::PluginWindowHandle id) {
+ shell_->webViewHost()->DestroyPluginContainer(id);
}
void TestWebViewDelegate::ShowJavaScriptAlert(const std::wstring& message) {
diff --git a/webkit/tools/test_shell/webview_host.h b/webkit/tools/test_shell/webview_host.h
index 962633b..3c95e1d 100644
--- a/webkit/tools/test_shell/webview_host.h
+++ b/webkit/tools/test_shell/webview_host.h
@@ -32,12 +32,11 @@ class WebViewHost : public WebWidgetHost {
WebView* webview() const;
#if defined(OS_LINUX)
- // Create a new plugin parent container, returning its X window id for
- // embedders to use.
- GdkNativeWindow CreatePluginContainer();
+ // Create a new plugin parent container for a given plugin XID.
+ void CreatePluginContainer(gfx::PluginWindowHandle id);
- // Called when a plugin has been destroyed. Lets us clean up our side.
- void OnPluginWindowDestroyed(GdkNativeWindow id);
+ // Destroy the plugin parent container when a plugin has been destroyed.
+ void DestroyPluginContainer(gfx::PluginWindowHandle id);
GtkPluginContainerManager* plugin_container_manager() {
return &plugin_container_manager_;
diff --git a/webkit/tools/test_shell/webview_host_gtk.cc b/webkit/tools/test_shell/webview_host_gtk.cc
index 39a88ab..6554cc5 100644
--- a/webkit/tools/test_shell/webview_host_gtk.cc
+++ b/webkit/tools/test_shell/webview_host_gtk.cc
@@ -35,10 +35,10 @@ WebView* WebViewHost::webview() const {
return static_cast<WebView*>(webwidget_);
}
-GdkNativeWindow WebViewHost::CreatePluginContainer() {
- return plugin_container_manager_.CreatePluginContainer();
+void WebViewHost::CreatePluginContainer(gfx::PluginWindowHandle id) {
+ plugin_container_manager_.CreatePluginContainer(id);
}
-void WebViewHost::OnPluginWindowDestroyed(GdkNativeWindow id) {
+void WebViewHost::DestroyPluginContainer(gfx::PluginWindowHandle id) {
plugin_container_manager_.DestroyPluginContainer(id);
}