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 | |
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
28 files changed, 177 insertions, 260 deletions
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index d028db5..422c313 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1429,8 +1429,6 @@ void RenderViewHost::OnMissingPluginStatus(int status) { void RenderViewHost::OnCrashedPlugin(base::ProcessId pid, const FilePath& plugin_path) { - view()->PluginProcessCrashed(pid); - RenderViewHostDelegate::BrowserIntegration* integration_delegate = delegate_->GetBrowserIntegrationDelegate(); if (integration_delegate) diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index c7d7e19..40fba47 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -782,15 +782,12 @@ void RenderWidgetHost::OnMsgImeUpdateStatus(int control, #if defined(OS_LINUX) -void RenderWidgetHost::OnMsgCreatePluginContainer( - base::ProcessId pid, - gfx::PluginWindowHandle* container) { - *container = view_->CreatePluginContainer(pid); +void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) { + view_->CreatePluginContainer(id); } -void RenderWidgetHost::OnMsgDestroyPluginContainer( - gfx::PluginWindowHandle container) { - view_->DestroyPluginContainer(container); +void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) { + view_->DestroyPluginContainer(id); } #elif defined(OS_MACOSX) diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 3b52e4a..242d56b 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -399,9 +399,8 @@ class RenderWidgetHost : public IPC::Channel::Listener, // having to bring in render_messages.h in a header file. void OnMsgImeUpdateStatus(int control, const gfx::Rect& caret_rect); #if defined(OS_LINUX) - void OnMsgCreatePluginContainer(base::ProcessId pid, - gfx::PluginWindowHandle* container); - void OnMsgDestroyPluginContainer(gfx::PluginWindowHandle container); + void OnMsgCreatePluginContainer(gfx::PluginWindowHandle id); + void OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id); #elif defined(OS_MACOSX) void OnMsgShowPopup(const ViewHostMsg_ShowPopup_Params& params); void OnMsgGetScreenInfo(gfx::NativeViewId view, diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index 31f1f64..b022f7e 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -161,13 +161,10 @@ class RenderWidgetHostView { #endif #if defined(OS_LINUX) - virtual gfx::PluginWindowHandle CreatePluginContainer( - base::ProcessId plugin_process_id) = 0; - virtual void DestroyPluginContainer(gfx::PluginWindowHandle container) = 0; + virtual void CreatePluginContainer(gfx::PluginWindowHandle id) = 0; + virtual void DestroyPluginContainer(gfx::PluginWindowHandle id) = 0; #endif - virtual void PluginProcessCrashed(base::ProcessId pid) { } - void set_activatable(bool activatable) { activatable_ = activatable; } diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index 48fed82..2353bb9 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -619,31 +619,12 @@ void RenderWidgetHostViewGtk::ReceivedSelectionText(GtkClipboard* clipboard, UTF8ToUTF16(text))); } -gfx::PluginWindowHandle RenderWidgetHostViewGtk::CreatePluginContainer( - base::ProcessId plugin_process_id) { - gfx::PluginWindowHandle handle = - plugin_container_manager_.CreatePluginContainer(); - plugin_pid_map_.insert(std::make_pair(plugin_process_id, handle)); - return handle; +void RenderWidgetHostViewGtk::CreatePluginContainer( + gfx::PluginWindowHandle id) { + plugin_container_manager_.CreatePluginContainer(id); } void RenderWidgetHostViewGtk::DestroyPluginContainer( - gfx::PluginWindowHandle container) { - plugin_container_manager_.DestroyPluginContainer(container); - - for (PluginPidMap::iterator i = plugin_pid_map_.begin(); - i != plugin_pid_map_.end(); ++i) { - if (i->second == container) { - plugin_pid_map_.erase(i); - break; - } - } -} - -void RenderWidgetHostViewGtk::PluginProcessCrashed(base::ProcessId pid) { - for (PluginPidMap::iterator i = plugin_pid_map_.find(pid); - i != plugin_pid_map_.end() && i->first == pid; ++i) { - plugin_container_manager_.DestroyPluginContainer(i->second); - } - plugin_pid_map_.erase(pid); + gfx::PluginWindowHandle id) { + plugin_container_manager_.DestroyPluginContainer(id); } diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h index 937e254..97ec6cf 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h @@ -64,10 +64,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView { virtual void PasteFromSelectionClipboard(); virtual void ShowingContextMenu(bool showing); virtual BackingStore* AllocBackingStore(const gfx::Size& size); - virtual gfx::PluginWindowHandle CreatePluginContainer( - base::ProcessId plugin_process_id); - virtual void DestroyPluginContainer(gfx::PluginWindowHandle container); - virtual void PluginProcessCrashed(base::ProcessId pid); + virtual void CreatePluginContainer(gfx::PluginWindowHandle id); + virtual void DestroyPluginContainer(gfx::PluginWindowHandle id); gfx::NativeView native_view() const { return view_.get(); } @@ -129,11 +127,6 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView { // Helper class that lets us allocate plugin containers and move them. GtkPluginContainerManager plugin_container_manager_; - - // A map of plugin process id -> windows related to that process. - // Lets us clean up immediately when a plugin process crashes. - typedef std::multimap<base::ProcessId, gfx::PluginWindowHandle> PluginPidMap; - PluginPidMap plugin_pid_map_; }; #endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_ diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index 6ea898b..537c149 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -83,10 +83,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { #endif #if defined(OS_LINUX) - virtual gfx::PluginWindowHandle CreatePluginContainer(base::ProcessId) { - return 0; - } - virtual void DestroyPluginContainer(gfx::PluginWindowHandle container) { } + virtual void CreatePluginContainer(gfx::PluginWindowHandle id) { } + virtual void DestroyPluginContainer(gfx::PluginWindowHandle id) { } #endif bool is_showing() const { return is_showing_; } diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index d2e2e64..4c1b985 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -238,15 +238,6 @@ IPC_BEGIN_MESSAGES(PluginHost) IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindow, gfx::PluginWindowHandle /* window */) -#if defined(OS_LINUX) - // Asks the renderer to create a plugin container (GtkSocket). - IPC_SYNC_MESSAGE_ROUTED0_1(PluginHostMsg_CreatePluginContainer, - gfx::PluginWindowHandle /* container */) - // Asks the renderer to destroy a plugin container (GtkSocket). - IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_DestroyPluginContainer, - gfx::PluginWindowHandle /* container */) -#endif - #if defined(OS_WIN) // The modal_loop_pump_messages_event parameter is an event handle which is // passed in for windowless plugins and is used to indicate if messages diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 45a409b..891dbb7 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1023,16 +1023,16 @@ IPC_BEGIN_MESSAGES(ViewHost) #if defined(OS_LINUX) // A renderer sends this when it needs a browser-side widget for - // hosting a windowed plugin. The PID is the PID of the *plugin* - // process, which is used to associate the browser-side container with - // the lifetime of the plugin process. - IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_CreatePluginContainer, - base::ProcessId /* pid */, - gfx::PluginWindowHandle /* container */) + // hosting a windowed plugin. id is the XID of the plugin window, for which + // the container is created. + IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_CreatePluginContainer, + gfx::PluginWindowHandle /* id */) // Destroy a plugin container previously created using CreatePluginContainer. + // id is the XID of the plugin window corresponding to the container that is + // to be destroyed. IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_DestroyPluginContainer, - gfx::PluginWindowHandle /* container */) + gfx::PluginWindowHandle /* id */) #endif // Clipboard IPC messages diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index 7d2598a..9a77484 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -5,9 +5,6 @@ #include "chrome/plugin/webplugin_proxy.h" #include "build/build_config.h" -#if defined(OS_LINUX) -#include <gtk/gtk.h> -#endif #include "app/gfx/canvas.h" #if defined(OS_WIN) @@ -56,11 +53,6 @@ WebPluginProxy::WebPluginProxy( delegate_(delegate), waiting_for_paint_(false), page_url_(page_url), -#if defined(OS_LINUX) - container_(0), - plug_(NULL), - socket_(NULL), -#endif ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)) { } @@ -74,42 +66,7 @@ bool WebPluginProxy::Send(IPC::Message* msg) { return channel_->Send(msg); } -#if defined(OS_LINUX) -gfx::PluginWindowHandle WebPluginProxy::CreatePluginContainer() { - DCHECK(!container_); - DCHECK(!plug_); - DCHECK(!socket_); - - Send(new PluginHostMsg_CreatePluginContainer(route_id_, &container_)); - if (!container_) - return 0; - - plug_ = gtk_plug_new(container_); - 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); - - return gtk_socket_get_id(GTK_SOCKET(socket_)); -} -#endif - void WebPluginProxy::SetWindow(gfx::PluginWindowHandle window) { -#if defined(OS_LINUX) - if (window) { - DCHECK(plug_); - DCHECK(socket_); - DCHECK_EQ(window, gtk_socket_get_id(GTK_SOCKET(socket_))); - window = container_; - } -#endif Send(new PluginHostMsg_SetWindow(route_id_, window)); } @@ -119,14 +76,7 @@ void WebPluginProxy::WillDestroyWindow(gfx::PluginWindowHandle window) { new PluginProcessHostMsg_PluginWindowDestroyed( window, ::GetParent(window))); #elif defined(OS_LINUX) - DCHECK(plug_); - DCHECK(socket_); - DCHECK_EQ(window, gtk_socket_get_id(GTK_SOCKET(socket_))); - Send(new PluginHostMsg_DestroyPluginContainer(route_id_, container_)); - gtk_widget_destroy(plug_); - container_ = NULL; - plug_ = NULL; - socket_ = NULL; + // Nothing to do. #else NOTIMPLEMENTED(); #endif diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 2b11e55..8e13638 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -42,9 +42,6 @@ class WebPluginProxy : public WebPlugin { ~WebPluginProxy(); // WebPlugin overrides -#if defined(OS_LINUX) - gfx::PluginWindowHandle CreatePluginContainer(); -#endif void SetWindow(gfx::PluginWindowHandle window); void WillDestroyWindow(gfx::PluginWindowHandle window); #if defined(OS_WIN) @@ -192,14 +189,6 @@ class WebPluginProxy : public WebPlugin { scoped_ptr<TransportDIB> background_dib_; scoped_ptr<skia::PlatformCanvas> windowless_canvas_; scoped_ptr<skia::PlatformCanvas> background_canvas_; - - // 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. container_ is the original container XID - // coming from the browser. - gfx::PluginWindowHandle container_; - GtkWidget *plug_; - GtkWidget *socket_; #endif ScopedRunnableMethodFactory<WebPluginProxy> runnable_method_factory_; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 442b929..48caa47 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -3305,7 +3305,18 @@ void RenderView::DidMovePlugin(const WebPluginGeometry& move) { SchedulePluginMove(move); } +void RenderView::CreatedPluginWindow(gfx::PluginWindowHandle window) { +#if defined(OS_LINUX) + RenderThread::current()->Send(new ViewHostMsg_CreatePluginContainer( + routing_id(), window)); +#endif +} + void RenderView::WillDestroyPluginWindow(gfx::PluginWindowHandle window) { +#if defined(OS_LINUX) + RenderThread::current()->Send(new ViewHostMsg_DestroyPluginContainer( + routing_id(), window)); +#endif CleanupWindowInPluginMoves(window); } diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 48923c4..7317385 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -328,6 +328,7 @@ class RenderView : public RenderWidget, virtual bool WasOpenedByUserGesture() const; virtual void FocusAccessibilityObject(WebCore::AccessibilityObject* acc_obj); virtual void DidMovePlugin(const WebPluginGeometry& move); + virtual void CreatedPluginWindow(gfx::PluginWindowHandle handle); virtual void WillDestroyPluginWindow(gfx::PluginWindowHandle handle); virtual void SpellCheck(const std::wstring& word, int* misspell_location, int* misspell_length); diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index db73717..dc6a104 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -187,6 +187,9 @@ WebPluginDelegateProxy::~WebPluginDelegateProxy() { } void WebPluginDelegateProxy::PluginDestroyed() { + if (window_) { + WillDestroyWindow(); + } plugin_ = NULL; if (npobject_) { @@ -358,12 +361,6 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy, msg) IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow, OnSetWindow) -#if defined(OS_LINUX) - IPC_MESSAGE_HANDLER(PluginHostMsg_CreatePluginContainer, - OnCreatePluginContainer) - IPC_MESSAGE_HANDLER(PluginHostMsg_DestroyPluginContainer, - OnDestroyPluginContainer) -#endif #if defined(OS_WIN) IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindowlessPumpEvent, OnSetWindowlessPumpEvent) @@ -399,7 +396,7 @@ void WebPluginDelegateProxy::OnChannelError() { if (window_) { // The actual WebPluginDelegate never got a chance to tell the WebPlugin // its window was going away. Do it on its behalf. - plugin_->WillDestroyWindow(window_); + WillDestroyWindow(); } plugin_->Invalidate(); } @@ -757,22 +754,14 @@ void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window) { plugin_->SetWindow(window); } -#if defined(OS_LINUX) -void WebPluginDelegateProxy::OnCreatePluginContainer( - gfx::PluginWindowHandle* container) { - RenderThread::current()->Send(new ViewHostMsg_CreatePluginContainer( - render_view_->routing_id(), GetProcessId(), container)); +void WebPluginDelegateProxy::WillDestroyWindow() { + DCHECK(window_); + plugin_->WillDestroyWindow(window_); + window_ = NULL; } -void WebPluginDelegateProxy::OnDestroyPluginContainer( - gfx::PluginWindowHandle container) { - RenderThread::current()->Send(new ViewHostMsg_DestroyPluginContainer( - render_view_->routing_id(), container)); -} -#endif - #if defined(OS_WIN) - void WebPluginDelegateProxy::OnSetWindowlessPumpEvent( +void WebPluginDelegateProxy::OnSetWindowlessPumpEvent( HANDLE modal_loop_pump_messages_event) { DCHECK(modal_loop_pump_messages_event_ == NULL); diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index 808c06e..5680d9e 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -108,10 +108,6 @@ class WebPluginDelegateProxy : public WebPluginDelegate, // Message handlers for messages that proxy WebPlugin methods, which // we translate into calls to the real WebPlugin. void OnSetWindow(gfx::PluginWindowHandle window); -#if defined(OS_LINUX) - void OnCreatePluginContainer(gfx::PluginWindowHandle* container); - void OnDestroyPluginContainer(gfx::PluginWindowHandle container); -#endif #if defined(OS_WIN) void OnSetWindowlessPumpEvent(HANDLE modal_loop_pump_messages_event); #endif @@ -163,6 +159,11 @@ class WebPluginDelegateProxy : public WebPluginDelegate, bool CreateBitmap(scoped_ptr<TransportDIB>* memory, scoped_ptr<skia::PlatformCanvas>* canvas); + // Called for cleanup during plugin destruction. Normally right before the + // plugin window gets destroyed, or when the plugin has crashed (at which + // point the window has already been destroyed). + void WillDestroyWindow(); + RenderView* render_view_; WebPlugin* plugin_; bool windowless_; 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); } |