| Index: webkit/glue/plugins/gtk_plugin_container_host.cc
|
| diff --git a/webkit/glue/plugins/gtk_plugin_container_host.cc b/webkit/glue/plugins/gtk_plugin_container_host.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e47e1c4146e9056521dd4da8a13eea8decf6696a
|
| --- /dev/null
|
| +++ b/webkit/glue/plugins/gtk_plugin_container_host.cc
|
| @@ -0,0 +1,138 @@
|
| +// 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_host.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 GtkPluginContainerHost::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 GtkPluginContainerHost::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 GtkPluginContainerHost::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* GtkPluginContainerHost::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 GtkPluginContainerHost::UnrealizeCallback(GtkWidget *widget,
|
| + void *user_data) {
|
| + // This is the last chance to get the XID for the widget. Remove it from the
|
| + // map here.
|
| + GtkPluginContainerHost* plugin_container_host =
|
| + static_cast<GtkPluginContainerHost*>(user_data);
|
| + gfx::PluginWindowHandle id = gtk_socket_get_id(GTK_SOCKET(widget));
|
| + plugin_container_host->plugin_window_to_widget_map_.erase(id);
|
| +}
|
|
|