1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/base/nsPluginNativeWindowGtk.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,341 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:expandtab:shiftwidth=2:tabstop=2: 1.6 +*/ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +/** 1.12 + * This file is the Gtk2 implementation of plugin native window. 1.13 + */ 1.14 + 1.15 +#include "nsDebug.h" 1.16 +#include "nsPluginNativeWindow.h" 1.17 +#include "nsNPAPIPlugin.h" 1.18 +#include "npapi.h" 1.19 +#include <gtk/gtk.h> 1.20 +#include <gdk/gdkx.h> 1.21 +#include <gdk/gdk.h> 1.22 + 1.23 +#include "gtk2xtbin.h" 1.24 +#include "mozilla/X11Util.h" 1.25 + 1.26 +class nsPluginNativeWindowGtk : public nsPluginNativeWindow { 1.27 +public: 1.28 + nsPluginNativeWindowGtk(); 1.29 + virtual ~nsPluginNativeWindowGtk(); 1.30 + 1.31 + virtual nsresult CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance); 1.32 +private: 1.33 + void SetWindow(XID aWindow) 1.34 + { 1.35 + window = reinterpret_cast<void*>(static_cast<uintptr_t>(aWindow)); 1.36 + } 1.37 + XID GetWindow() const 1.38 + { 1.39 + return static_cast<XID>(reinterpret_cast<uintptr_t>(window)); 1.40 + } 1.41 + 1.42 + NPSetWindowCallbackStruct mWsInfo; 1.43 + /** 1.44 + * Either a GtkSocket or a special GtkXtBin widget (derived from GtkSocket) 1.45 + * that encapsulates the Xt toolkit within a Gtk Application. 1.46 + */ 1.47 + GtkWidget* mSocketWidget; 1.48 + nsresult CreateXEmbedWindow(bool aEnableXtFocus); 1.49 +#if (MOZ_WIDGET_GTK == 2) 1.50 + nsresult CreateXtWindow(); 1.51 +#endif 1.52 + void SetAllocation(); 1.53 +}; 1.54 + 1.55 +static gboolean plug_removed_cb (GtkWidget *widget, gpointer data); 1.56 +static void socket_unrealize_cb (GtkWidget *widget, gpointer data); 1.57 + 1.58 +nsPluginNativeWindowGtk::nsPluginNativeWindowGtk() : nsPluginNativeWindow() 1.59 +{ 1.60 + // initialize the struct fields 1.61 + window = nullptr; 1.62 + x = 0; 1.63 + y = 0; 1.64 + width = 0; 1.65 + height = 0; 1.66 + memset(&clipRect, 0, sizeof(clipRect)); 1.67 + ws_info = &mWsInfo; 1.68 + type = NPWindowTypeWindow; 1.69 + mSocketWidget = 0; 1.70 + mWsInfo.type = 0; 1.71 + mWsInfo.display = nullptr; 1.72 + mWsInfo.visual = nullptr; 1.73 + mWsInfo.colormap = 0; 1.74 + mWsInfo.depth = 0; 1.75 +} 1.76 + 1.77 +nsPluginNativeWindowGtk::~nsPluginNativeWindowGtk() 1.78 +{ 1.79 + if(mSocketWidget) { 1.80 + gtk_widget_destroy(mSocketWidget); 1.81 + } 1.82 +} 1.83 + 1.84 +nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) 1.85 +{ 1.86 + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); 1.87 + *aPluginNativeWindow = new nsPluginNativeWindowGtk(); 1.88 + return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY; 1.89 +} 1.90 + 1.91 +nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow) 1.92 +{ 1.93 + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); 1.94 + nsPluginNativeWindowGtk *p = (nsPluginNativeWindowGtk *)aPluginNativeWindow; 1.95 + delete p; 1.96 + return NS_OK; 1.97 +} 1.98 + 1.99 +nsresult nsPluginNativeWindowGtk::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance) 1.100 +{ 1.101 + if (aPluginInstance) { 1.102 + if (type == NPWindowTypeWindow) { 1.103 + if (!mSocketWidget) { 1.104 + nsresult rv; 1.105 + 1.106 + // The documentation on the types for many variables in NP(N|P)_GetValue 1.107 + // is vague. Often boolean values are NPBool (1 byte), but 1.108 + // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins 1.109 + // treats NPPVpluginNeedsXEmbed as PRBool (int), and 1.110 + // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|. 1.111 + // thus we can't use NPBool for needsXEmbed, or the three bytes above 1.112 + // it on the stack would get clobbered. so protect with the larger bool. 1.113 + int needsXEmbed = 0; 1.114 + rv = aPluginInstance->GetValueFromPlugin(NPPVpluginNeedsXEmbed, &needsXEmbed); 1.115 + // If the call returned an error code make sure we still use our default value. 1.116 + if (NS_FAILED(rv)) { 1.117 + needsXEmbed = 0; 1.118 + } 1.119 +#ifdef DEBUG 1.120 + printf("nsPluginNativeWindowGtk: NPPVpluginNeedsXEmbed=%d\n", needsXEmbed); 1.121 +#endif 1.122 + 1.123 + bool isOOPPlugin = aPluginInstance->GetPlugin()->GetLibrary()->IsOOP(); 1.124 + if (needsXEmbed || isOOPPlugin) { 1.125 + bool enableXtFocus = !needsXEmbed; 1.126 + rv = CreateXEmbedWindow(enableXtFocus); 1.127 + } 1.128 + else { 1.129 +#if (MOZ_WIDGET_GTK == 2) 1.130 + rv = CreateXtWindow(); 1.131 +#else 1.132 + return NS_ERROR_FAILURE; 1.133 +#endif 1.134 + } 1.135 + 1.136 + if (NS_FAILED(rv)) { 1.137 + return NS_ERROR_FAILURE; 1.138 + } 1.139 + } 1.140 + 1.141 + if (!mSocketWidget) { 1.142 + return NS_ERROR_FAILURE; 1.143 + } 1.144 + 1.145 + // Make sure to resize and re-place the window if required. 1.146 + SetAllocation(); 1.147 + // Need to reset "window" each time as nsObjectFrame::DidReflow sets it 1.148 + // to the ancestor window. 1.149 +#if (MOZ_WIDGET_GTK == 2) 1.150 + if (GTK_IS_XTBIN(mSocketWidget)) { 1.151 + // Point the NPWindow structures window to the actual X window 1.152 + SetWindow(GTK_XTBIN(mSocketWidget)->xtwindow); 1.153 + } 1.154 + else { // XEmbed or OOP&Xt 1.155 + SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget))); 1.156 + } 1.157 +#else 1.158 + // Gtk3 supports only OOP by GtkSocket 1.159 + SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget))); 1.160 +#endif 1.161 + 1.162 +#ifdef DEBUG 1.163 + printf("nsPluginNativeWindowGtk: call SetWindow with xid=%p\n", (void *)window); 1.164 +#endif 1.165 + } // NPWindowTypeWindow 1.166 + aPluginInstance->SetWindow(this); 1.167 + } 1.168 + else if (mPluginInstance) 1.169 + mPluginInstance->SetWindow(nullptr); 1.170 + 1.171 + SetPluginInstance(aPluginInstance); 1.172 + return NS_OK; 1.173 +} 1.174 + 1.175 +nsresult nsPluginNativeWindowGtk::CreateXEmbedWindow(bool aEnableXtFocus) { 1.176 + NS_ASSERTION(!mSocketWidget,"Already created a socket widget!"); 1.177 + GdkDisplay *display = gdk_display_get_default(); 1.178 + GdkWindow *parent_win = gdk_x11_window_lookup_for_display(display, GetWindow()); 1.179 + mSocketWidget = gtk_socket_new(); 1.180 + 1.181 + //attach the socket to the container widget 1.182 + gtk_widget_set_parent_window(mSocketWidget, parent_win); 1.183 + 1.184 + // enable/disable focus event handlers, 1.185 + // see plugin_window_filter_func() for details 1.186 + g_object_set_data(G_OBJECT(mSocketWidget), "enable-xt-focus", (void *)aEnableXtFocus); 1.187 + 1.188 + // Make sure to handle the plug_removed signal. If we don't the 1.189 + // socket will automatically be destroyed when the plug is 1.190 + // removed, which means we're destroying it more than once. 1.191 + // SYNTAX ERROR. 1.192 + g_signal_connect(mSocketWidget, "plug_removed", 1.193 + G_CALLBACK(plug_removed_cb), nullptr); 1.194 + 1.195 + g_signal_connect(mSocketWidget, "unrealize", 1.196 + G_CALLBACK(socket_unrealize_cb), nullptr); 1.197 + 1.198 + g_signal_connect(mSocketWidget, "destroy", 1.199 + G_CALLBACK(gtk_widget_destroyed), &mSocketWidget); 1.200 + 1.201 + gpointer user_data = nullptr; 1.202 + gdk_window_get_user_data(parent_win, &user_data); 1.203 + 1.204 + GtkContainer *container = GTK_CONTAINER(user_data); 1.205 + gtk_container_add(container, mSocketWidget); 1.206 + gtk_widget_realize(mSocketWidget); 1.207 + 1.208 + // The GtkSocket has a visible window, but the plugin's XEmbed plug will 1.209 + // cover this window. Normally GtkSockets let the X server paint their 1.210 + // background and this would happen immediately (before the plug is 1.211 + // created). Setting the background to None prevents the server from 1.212 + // painting this window, avoiding flicker. 1.213 + // TODO GTK3 1.214 +#if (MOZ_WIDGET_GTK == 2) 1.215 + gdk_window_set_back_pixmap(gtk_widget_get_window(mSocketWidget), nullptr, FALSE); 1.216 +#endif 1.217 + 1.218 + // Resize before we show 1.219 + SetAllocation(); 1.220 + 1.221 + gtk_widget_show(mSocketWidget); 1.222 + 1.223 + gdk_flush(); 1.224 + SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget))); 1.225 + 1.226 + // Fill out the ws_info structure. 1.227 + // (The windowless case is done in nsObjectFrame.cpp.) 1.228 + GdkWindow *gdkWindow = gdk_x11_window_lookup_for_display(display, GetWindow()); 1.229 + if(!gdkWindow) 1.230 + return NS_ERROR_FAILURE; 1.231 + 1.232 + mWsInfo.display = GDK_WINDOW_XDISPLAY(gdkWindow); 1.233 +#if (MOZ_WIDGET_GTK == 2) 1.234 + mWsInfo.colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gdkWindow)); 1.235 + GdkVisual* gdkVisual = gdk_drawable_get_visual(gdkWindow); 1.236 + mWsInfo.depth = gdkVisual->depth; 1.237 +#else 1.238 + mWsInfo.colormap = None; 1.239 + GdkVisual* gdkVisual = gdk_window_get_visual(gdkWindow); 1.240 + mWsInfo.depth = gdk_visual_get_depth(gdkVisual); 1.241 +#endif 1.242 + mWsInfo.visual = GDK_VISUAL_XVISUAL(gdkVisual); 1.243 + 1.244 + return NS_OK; 1.245 +} 1.246 + 1.247 +void nsPluginNativeWindowGtk::SetAllocation() { 1.248 + if (!mSocketWidget) 1.249 + return; 1.250 + 1.251 + GtkAllocation new_allocation; 1.252 + new_allocation.x = 0; 1.253 + new_allocation.y = 0; 1.254 + new_allocation.width = width; 1.255 + new_allocation.height = height; 1.256 + gtk_widget_size_allocate(mSocketWidget, &new_allocation); 1.257 +} 1.258 + 1.259 +#if (MOZ_WIDGET_GTK == 2) 1.260 +nsresult nsPluginNativeWindowGtk::CreateXtWindow() { 1.261 + NS_ASSERTION(!mSocketWidget,"Already created a socket widget!"); 1.262 + 1.263 +#ifdef DEBUG 1.264 + printf("About to create new xtbin of %i X %i from %p...\n", 1.265 + width, height, (void*)window); 1.266 +#endif 1.267 + GdkDisplay *display = gdk_display_get_default(); 1.268 + GdkWindow *gdkWindow = gdk_x11_window_lookup_for_display(display, GetWindow()); 1.269 + mSocketWidget = gtk_xtbin_new(gdkWindow, 0); 1.270 + // Check to see if creating the xtbin failed for some reason. 1.271 + // if it did, we can't go any further. 1.272 + if (!mSocketWidget) 1.273 + return NS_ERROR_FAILURE; 1.274 + 1.275 + g_signal_connect(mSocketWidget, "destroy", 1.276 + G_CALLBACK(gtk_widget_destroyed), &mSocketWidget); 1.277 + 1.278 + gtk_widget_set_size_request(mSocketWidget, width, height); 1.279 + 1.280 +#ifdef DEBUG 1.281 + printf("About to show xtbin(%p)...\n", (void*)mSocketWidget); fflush(nullptr); 1.282 +#endif 1.283 + gtk_widget_show(mSocketWidget); 1.284 +#ifdef DEBUG 1.285 + printf("completed gtk_widget_show(%p)\n", (void*)mSocketWidget); fflush(nullptr); 1.286 +#endif 1.287 + 1.288 + // Fill out the ws_info structure. 1.289 + GtkXtBin* xtbin = GTK_XTBIN(mSocketWidget); 1.290 + // The xtbin has its own Display structure. 1.291 + mWsInfo.display = xtbin->xtdisplay; 1.292 + mWsInfo.colormap = xtbin->xtclient.xtcolormap; 1.293 + mWsInfo.visual = xtbin->xtclient.xtvisual; 1.294 + mWsInfo.depth = xtbin->xtclient.xtdepth; 1.295 + // Leave mWsInfo.type = 0 - Who knows what this is meant to be? 1.296 + 1.297 + XFlush(mWsInfo.display); 1.298 + 1.299 + return NS_OK; 1.300 +} 1.301 +#endif 1.302 + 1.303 +/* static */ 1.304 +gboolean 1.305 +plug_removed_cb (GtkWidget *widget, gpointer data) 1.306 +{ 1.307 + // Gee, thanks for the info! 1.308 + return TRUE; 1.309 +} 1.310 + 1.311 +static void 1.312 +socket_unrealize_cb(GtkWidget *widget, gpointer data) 1.313 +{ 1.314 + // Unmap and reparent any child windows that GDK does not yet know about. 1.315 + // (See bug 540114 comment 10.) 1.316 + GdkWindow* socket_window = gtk_widget_get_window(widget); 1.317 + GdkDisplay* gdkDisplay = gdk_display_get_default(); 1.318 + Display* display = GDK_DISPLAY_XDISPLAY(gdkDisplay); 1.319 + 1.320 + // Ignore X errors that may happen if windows get destroyed (possibly 1.321 + // requested by the plugin) between XQueryTree and when we operate on them. 1.322 + gdk_error_trap_push(); 1.323 + 1.324 + Window root, parent; 1.325 + Window* children; 1.326 + unsigned int nchildren; 1.327 + if (!XQueryTree(display, gdk_x11_window_get_xid(socket_window), 1.328 + &root, &parent, &children, &nchildren)) 1.329 + return; 1.330 + 1.331 + for (unsigned int i = 0; i < nchildren; ++i) { 1.332 + Window child = children[i]; 1.333 + if (!gdk_x11_window_lookup_for_display(gdkDisplay, child)) { 1.334 + // This window is not known to GDK. 1.335 + XUnmapWindow(display, child); 1.336 + XReparentWindow(display, child, DefaultRootWindow(display), 0, 0); 1.337 + } 1.338 + } 1.339 + 1.340 + if (children) XFree(children); 1.341 + 1.342 + mozilla::FinishX(display); 1.343 + gdk_error_trap_pop(); 1.344 +}