summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authortschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-20 19:13:00 +0000
committertschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-20 19:13:00 +0000
commited0ea691fc4b2fa9a54faded95d3153847597bcb (patch)
tree9e63778043ee73dc1805a9828971aa9dcb1a22b1 /o3d
parent6b7624085b86448683e25006558a4e5b9c02bd66 (diff)
downloadchromium_src-ed0ea691fc4b2fa9a54faded95d3153847597bcb.zip
chromium_src-ed0ea691fc4b2fa9a54faded95d3153847597bcb.tar.gz
chromium_src-ed0ea691fc4b2fa9a54faded95d3153847597bcb.tar.bz2
Linux: fix crash in Firefox at plugin unload time when more than one O3D instance is running. The problem here was that Firefox has a bug where closing a tab actually deletes the parent windows of the plugin _before_ calling NPP_Destroy(), and Gtk recursively destroys all children automatically. Hence, once NPP_Destroy() runs our X11 Window handle is already invalid. If there is another O3D instance running in the same browser process, then performing the TearDown() call requires a MakeCurrent() call on the Window handle, which will fail with GLXBadDrawable and kill the browser. The solution requires two things. First, to avoid Gtk recursively destroying the children, we explicitly open a separate X11 connection for our GtkPlug, which means a destroy on the parents does not automatically propagate to the children because it has to go through the X server first. Second, we register a callback with our GtkPlug to handle this event from the X server by turning our GtkPlug into a hidden unparented window rather than destroying it.
Unrelatedly, also make fullscreen windows be set_keep_above and fix some spurious unref() calls (which produced warnings but otherwise were mostly harmless). TEST=opening and closing concurrent ping pong windows in FF and Chrome (64-bit) Review URL: http://codereview.chromium.org/553028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36650 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/plugin/cross/o3d_glue.cc1
-rw-r--r--o3d/plugin/cross/o3d_glue.h1
-rw-r--r--o3d/plugin/linux/main_linux.cc26
3 files changed, 21 insertions, 7 deletions
diff --git a/o3d/plugin/cross/o3d_glue.cc b/o3d/plugin/cross/o3d_glue.cc
index 1914ac8..18b31c6 100644
--- a/o3d/plugin/cross/o3d_glue.cc
+++ b/o3d/plugin/cross/o3d_glue.cc
@@ -144,6 +144,7 @@ PluginObject::PluginObject(NPP npp)
xt_interval_(0),
last_click_time_(0),
drawable_(0),
+ gdk_display_(NULL),
gtk_container_(NULL),
gtk_fullscreen_container_(NULL),
gtk_event_source_(NULL),
diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h
index 2375173..d732c13 100644
--- a/o3d/plugin/cross/o3d_glue.h
+++ b/o3d/plugin/cross/o3d_glue.h
@@ -291,6 +291,7 @@ class PluginObject: public NPObject {
// XEmbed mode
Window drawable_;
+ GdkDisplay *gdk_display_;
GtkWidget *gtk_container_;
GtkWidget *gtk_fullscreen_container_;
GtkWidget *gtk_event_source_;
diff --git a/o3d/plugin/linux/main_linux.cc b/o3d/plugin/linux/main_linux.cc
index 9162a91..2b3e89e 100644
--- a/o3d/plugin/linux/main_linux.cc
+++ b/o3d/plugin/linux/main_linux.cc
@@ -718,6 +718,8 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save) {
HANDLE_CRASHES;
PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
if (obj) {
+ obj->TearDown();
+
if (obj->xt_widget_) {
// NOTE: This crashes. Not sure why, possibly the widget has
// already been destroyed, but we haven't received a SetWindow(NULL).
@@ -735,24 +737,24 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save) {
}
if (obj->gtk_container_) {
gtk_widget_destroy(obj->gtk_container_);
- gtk_widget_unref(obj->gtk_container_);
obj->gtk_container_ = NULL;
}
if (obj->gtk_fullscreen_container_) {
gtk_widget_destroy(obj->gtk_fullscreen_container_);
- gtk_widget_unref(obj->gtk_fullscreen_container_);
- obj->gtk_container_ = NULL;
+ obj->gtk_fullscreen_container_ = NULL;
+ }
+ if (obj->gdk_display_) {
+ gdk_display_close(obj->gdk_display_);
+ obj->gdk_display_ = NULL;
}
obj->gtk_event_source_ = NULL;
obj->event_handler_id_ = 0;
obj->window_ = 0;
obj->drawable_ = 0;
- obj->TearDown();
NPN_ReleaseObject(obj);
instance->pdata = NULL;
}
-
return NPERR_NO_ERROR;
}
@@ -769,7 +771,17 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window) {
if (g_xembed_support) {
// We asked for a XEmbed plugin, the xwindow is a GtkSocket, we create
// a GtkPlug to go into it.
- obj->gtk_container_ = gtk_plug_new(xwindow);
+ obj->gdk_display_ = gdk_display_open(XDisplayString(display));
+ LOG_ASSERT(obj->gdk_display_) << "Unable to open X11 display";
+ display = GDK_DISPLAY_XDISPLAY(obj->gdk_display_);
+ obj->gtk_container_ =
+ gtk_plug_new_for_display(obj->gdk_display_, xwindow);
+ // Firefox has a bug where it sometimes destroys our parent widget before
+ // calling NPP_Destroy. We handle this by hiding our X window instead of
+ // destroying it. Without this, future OpenGL calls can raise a
+ // GLXBadDrawable error and kill the browser process.
+ g_signal_connect(G_OBJECT(obj->gtk_container_), "delete-event",
+ G_CALLBACK(gtk_widget_hide_on_delete), NULL);
gtk_widget_set_double_buffered(obj->gtk_container_, FALSE);
if (!obj->fullscreen()) {
obj->SetGtkEventSource(obj->gtk_container_);
@@ -921,6 +933,7 @@ bool PluginObject::RequestFullscreenDisplay() {
// Stops Gtk from writing an off-screen buffer to the display, which conflicts
// with our GL rendering.
gtk_widget_set_double_buffered(widget, FALSE);
+ gtk_window_set_keep_above(window, TRUE);
GdkScreen *screen = gtk_window_get_screen(window);
// In the case of Xinerama or TwinView, these will be the dimensions of the
// whole desktop, which is wrong, but the window manager is smart enough to
@@ -961,7 +974,6 @@ void PluginObject::CancelFullscreenDisplay() {
false);
SetGtkEventSource(gtk_container_);
gtk_widget_destroy(gtk_fullscreen_container_);
- gtk_widget_unref(gtk_fullscreen_container_);
gtk_fullscreen_container_ = NULL;
fullscreen_window_ = 0;
fullscreen_ = false;