diff options
author | tschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-20 19:13:00 +0000 |
---|---|---|
committer | tschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-20 19:13:00 +0000 |
commit | ed0ea691fc4b2fa9a54faded95d3153847597bcb (patch) | |
tree | 9e63778043ee73dc1805a9828971aa9dcb1a22b1 /o3d | |
parent | 6b7624085b86448683e25006558a4e5b9c02bd66 (diff) | |
download | chromium_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.cc | 1 | ||||
-rw-r--r-- | o3d/plugin/cross/o3d_glue.h | 1 | ||||
-rw-r--r-- | o3d/plugin/linux/main_linux.cc | 26 |
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; |