diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-07 17:40:46 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-07 17:40:46 +0000 |
commit | 700d3d58213d15dea1beb2f7f7122e77e7ea2a47 (patch) | |
tree | 5d6a3c72fa58cccd7a7f7ddba5c77ed0edbe5135 /webkit/glue/plugins | |
parent | d1ae85447a12e97b0758b0d113a12e2d6c6d09b4 (diff) | |
download | chromium_src-700d3d58213d15dea1beb2f7f7122e77e7ea2a47.zip chromium_src-700d3d58213d15dea1beb2f7f7122e77e7ea2a47.tar.gz chromium_src-700d3d58213d15dea1beb2f7f7122e77e7ea2a47.tar.bz2 |
linux: OOP windowed plugins
There are still a few issues, but that's a start.
- only windowed plugins
- we can't currently create the gtksocket in background tabs, because their gtkwidgets are not yet in the hierarchy, so they can't be realized (that's what gives the XID).
- the plugin process talks to the browser process through the renderer process to create/destroy the gtksockets, because the plugin doesn't know which renderer it's talking to. We need a bit more plumbing to be able to have direct IPC.
- some code is duplicated between chrome and test_shell. We should probably refactor it, but I'm not sure where the common part should live.
Patch from Antoine Labour <piman@google.com>, with some touchups by me.
Review URL: http://codereview.chromium.org/146078
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20041 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/plugins')
-rw-r--r-- | webkit/glue/plugins/gtk_plugin_container_manager.cc | 139 | ||||
-rw-r--r-- | webkit/glue/plugins/gtk_plugin_container_manager.h | 49 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_gtk.cc | 3 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 23 |
4 files changed, 193 insertions, 21 deletions
diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.cc b/webkit/glue/plugins/gtk_plugin_container_manager.cc new file mode 100644 index 0000000..e251cca --- /dev/null +++ b/webkit/glue/plugins/gtk_plugin_container_manager.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/glue/plugins/gtk_plugin_container_manager.h" + +#include <gtk/gtk.h> + +#include "base/gfx/gtk_util.h" +#include "base/logging.h" +#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() { + 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; +} + +void GtkPluginContainerManager::DestroyPluginContainer( + gfx::PluginWindowHandle container) { + GtkWidget* plugin_container = MapIDToWidget(container); + if (!plugin_container) + return; + + // This will call the UnrealizeCallback that will remove plugin_container + // from the map. + gtk_widget_destroy(plugin_container); +} + +void GtkPluginContainerManager::MovePluginContainer( + const WebPluginGeometry& move) { + DCHECK(host_widget_); + GtkWidget *widget = MapIDToWidget(move.window); + if (!widget) + return; + + DCHECK(!GTK_WIDGET_NO_WINDOW(widget)); + DCHECK(GTK_WIDGET_REALIZED(widget)); + + if (!move.visible) { + gtk_widget_hide(widget); + return; + } else { + gtk_widget_show(widget); + } + + GdkRectangle clip_rect = move.clip_rect.ToGdkRectangle(); + GdkRegion* clip_region = gdk_region_rectangle(&clip_rect); + gfx::SubtractRectanglesFromRegion(clip_region, move.cutout_rects); + gdk_window_shape_combine_region(widget->window, clip_region, 0, 0); + gdk_region_destroy(clip_region); + + // Update the window position. Resizing is handled by WebPluginDelegate. + // TODO(deanm): Verify that we only need to move and not resize. + // TODO(evanm): we should cache the last shape and position and skip all + // of this business in the common case where nothing has changed. + int current_x, current_y; + + // Until the above TODO is resolved, we can grab the last position + // off of the GtkFixed with a bit of hackery. + GValue value = {0}; + g_value_init(&value, G_TYPE_INT); + gtk_container_child_get_property(GTK_CONTAINER(host_widget_), widget, + "x", &value); + current_x = g_value_get_int(&value); + gtk_container_child_get_property(GTK_CONTAINER(host_widget_), widget, + "y", &value); + current_y = g_value_get_int(&value); + g_value_unset(&value); + + if (move.window_rect.x() != current_x || + move.window_rect.y() != current_y) { + // Calling gtk_fixed_move unnecessarily is a no-no, as it causes the + // parent window to repaint! + gtk_fixed_move(GTK_FIXED(host_widget_), + widget, + move.window_rect.x(), + move.window_rect.y()); + } + + gtk_plugin_container_set_size(widget, + move.window_rect.width(), + move.window_rect.height()); +} + +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()) + return i->second; + + LOG(ERROR) << "Request for widget host for unknown window id " << id; + + return NULL; +} + +gboolean 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. + 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); +} diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.h b/webkit/glue/plugins/gtk_plugin_container_manager.h new file mode 100644 index 0000000..fa1156a --- /dev/null +++ b/webkit/glue/plugins/gtk_plugin_container_manager.h @@ -0,0 +1,49 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_MANAGER_H_ +#define WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_MANAGER_H_ + +#include <gtk/gtk.h> +#include <map> +#include "base/gfx/native_widget_types.h" + +typedef struct _GtkWidget GtkWidget; +struct WebPluginGeometry; + +// Helper class that creates and manages plugin containers (GtkSocket). +class GtkPluginContainerManager { + public: + GtkPluginContainerManager() : host_widget_(NULL) { } + + // 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(); + + // Destroys a plugin container, given its XID. + void DestroyPluginContainer(gfx::PluginWindowHandle container); + + // 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. + 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 gboolean UnrealizeCallback(GtkWidget *widget, void *user_data); + + // Parent of the plugin containers. + GtkWidget* host_widget_; + + // A map that associates plugin containers to their XID. + typedef std::map<gfx::PluginWindowHandle, GtkWidget*> PluginWindowToWidgetMap; + PluginWindowToWidgetMap plugin_window_to_widget_map_; +}; + +#endif // WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_MANAGER_H_ diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc index 9f9838b..87d8685 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc @@ -266,6 +266,9 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() { // Xembed plugins need a window created for them browser-side. // Do that now. windowed_handle_ = plugin_->CreatePluginContainer(); + if (!windowed_handle_) + return false; + window_.window = reinterpret_cast<void*>(windowed_handle_); if (!window_.ws_info) diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index 54bf43b..771c31a 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -58,7 +58,7 @@ WebPluginDelegateImpl* g_current_plugin_instance = NULL; WebPluginDelegate* WebPluginDelegate::Create( const FilePath& filename, const std::string& mime_type, - gfx::NativeView containing_view) { + gfx::PluginWindowHandle containing_view) { scoped_refptr<NPAPI::PluginLib> plugin = NPAPI::PluginLib::CreatePluginLib(filename); if (plugin.get() == NULL) @@ -73,27 +73,8 @@ WebPluginDelegate* WebPluginDelegate::Create( return new WebPluginDelegateImpl(containing_view, instance.get()); } -bool WebPluginDelegateImpl::IsPluginDelegateWindow(gfx::NativeWindow window) { - return false; -} - -bool WebPluginDelegateImpl::GetPluginNameFromWindow( - gfx::NativeWindow window, std::wstring *plugin_name) { - if (NULL == plugin_name) { - return false; - } - if (!IsPluginDelegateWindow(window)) { - return false; - } - return false; -} - -bool WebPluginDelegateImpl::IsDummyActivationWindow(gfx::NativeWindow window) { - return false; -} - WebPluginDelegateImpl::WebPluginDelegateImpl( - gfx::NativeView containing_view, + gfx::PluginWindowHandle containing_view, NPAPI::PluginInstance *instance) : parent_(containing_view), instance_(instance), |