dom/plugins/base/nsPluginNativeWindowGtk.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:expandtab:shiftwidth=2:tabstop=2:
michael@0 3 */
michael@0 4 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 /**
michael@0 9 * This file is the Gtk2 implementation of plugin native window.
michael@0 10 */
michael@0 11
michael@0 12 #include "nsDebug.h"
michael@0 13 #include "nsPluginNativeWindow.h"
michael@0 14 #include "nsNPAPIPlugin.h"
michael@0 15 #include "npapi.h"
michael@0 16 #include <gtk/gtk.h>
michael@0 17 #include <gdk/gdkx.h>
michael@0 18 #include <gdk/gdk.h>
michael@0 19
michael@0 20 #include "gtk2xtbin.h"
michael@0 21 #include "mozilla/X11Util.h"
michael@0 22
michael@0 23 class nsPluginNativeWindowGtk : public nsPluginNativeWindow {
michael@0 24 public:
michael@0 25 nsPluginNativeWindowGtk();
michael@0 26 virtual ~nsPluginNativeWindowGtk();
michael@0 27
michael@0 28 virtual nsresult CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance);
michael@0 29 private:
michael@0 30 void SetWindow(XID aWindow)
michael@0 31 {
michael@0 32 window = reinterpret_cast<void*>(static_cast<uintptr_t>(aWindow));
michael@0 33 }
michael@0 34 XID GetWindow() const
michael@0 35 {
michael@0 36 return static_cast<XID>(reinterpret_cast<uintptr_t>(window));
michael@0 37 }
michael@0 38
michael@0 39 NPSetWindowCallbackStruct mWsInfo;
michael@0 40 /**
michael@0 41 * Either a GtkSocket or a special GtkXtBin widget (derived from GtkSocket)
michael@0 42 * that encapsulates the Xt toolkit within a Gtk Application.
michael@0 43 */
michael@0 44 GtkWidget* mSocketWidget;
michael@0 45 nsresult CreateXEmbedWindow(bool aEnableXtFocus);
michael@0 46 #if (MOZ_WIDGET_GTK == 2)
michael@0 47 nsresult CreateXtWindow();
michael@0 48 #endif
michael@0 49 void SetAllocation();
michael@0 50 };
michael@0 51
michael@0 52 static gboolean plug_removed_cb (GtkWidget *widget, gpointer data);
michael@0 53 static void socket_unrealize_cb (GtkWidget *widget, gpointer data);
michael@0 54
michael@0 55 nsPluginNativeWindowGtk::nsPluginNativeWindowGtk() : nsPluginNativeWindow()
michael@0 56 {
michael@0 57 // initialize the struct fields
michael@0 58 window = nullptr;
michael@0 59 x = 0;
michael@0 60 y = 0;
michael@0 61 width = 0;
michael@0 62 height = 0;
michael@0 63 memset(&clipRect, 0, sizeof(clipRect));
michael@0 64 ws_info = &mWsInfo;
michael@0 65 type = NPWindowTypeWindow;
michael@0 66 mSocketWidget = 0;
michael@0 67 mWsInfo.type = 0;
michael@0 68 mWsInfo.display = nullptr;
michael@0 69 mWsInfo.visual = nullptr;
michael@0 70 mWsInfo.colormap = 0;
michael@0 71 mWsInfo.depth = 0;
michael@0 72 }
michael@0 73
michael@0 74 nsPluginNativeWindowGtk::~nsPluginNativeWindowGtk()
michael@0 75 {
michael@0 76 if(mSocketWidget) {
michael@0 77 gtk_widget_destroy(mSocketWidget);
michael@0 78 }
michael@0 79 }
michael@0 80
michael@0 81 nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
michael@0 82 {
michael@0 83 NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
michael@0 84 *aPluginNativeWindow = new nsPluginNativeWindowGtk();
michael@0 85 return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 86 }
michael@0 87
michael@0 88 nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
michael@0 89 {
michael@0 90 NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
michael@0 91 nsPluginNativeWindowGtk *p = (nsPluginNativeWindowGtk *)aPluginNativeWindow;
michael@0 92 delete p;
michael@0 93 return NS_OK;
michael@0 94 }
michael@0 95
michael@0 96 nsresult nsPluginNativeWindowGtk::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance)
michael@0 97 {
michael@0 98 if (aPluginInstance) {
michael@0 99 if (type == NPWindowTypeWindow) {
michael@0 100 if (!mSocketWidget) {
michael@0 101 nsresult rv;
michael@0 102
michael@0 103 // The documentation on the types for many variables in NP(N|P)_GetValue
michael@0 104 // is vague. Often boolean values are NPBool (1 byte), but
michael@0 105 // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins
michael@0 106 // treats NPPVpluginNeedsXEmbed as PRBool (int), and
michael@0 107 // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|.
michael@0 108 // thus we can't use NPBool for needsXEmbed, or the three bytes above
michael@0 109 // it on the stack would get clobbered. so protect with the larger bool.
michael@0 110 int needsXEmbed = 0;
michael@0 111 rv = aPluginInstance->GetValueFromPlugin(NPPVpluginNeedsXEmbed, &needsXEmbed);
michael@0 112 // If the call returned an error code make sure we still use our default value.
michael@0 113 if (NS_FAILED(rv)) {
michael@0 114 needsXEmbed = 0;
michael@0 115 }
michael@0 116 #ifdef DEBUG
michael@0 117 printf("nsPluginNativeWindowGtk: NPPVpluginNeedsXEmbed=%d\n", needsXEmbed);
michael@0 118 #endif
michael@0 119
michael@0 120 bool isOOPPlugin = aPluginInstance->GetPlugin()->GetLibrary()->IsOOP();
michael@0 121 if (needsXEmbed || isOOPPlugin) {
michael@0 122 bool enableXtFocus = !needsXEmbed;
michael@0 123 rv = CreateXEmbedWindow(enableXtFocus);
michael@0 124 }
michael@0 125 else {
michael@0 126 #if (MOZ_WIDGET_GTK == 2)
michael@0 127 rv = CreateXtWindow();
michael@0 128 #else
michael@0 129 return NS_ERROR_FAILURE;
michael@0 130 #endif
michael@0 131 }
michael@0 132
michael@0 133 if (NS_FAILED(rv)) {
michael@0 134 return NS_ERROR_FAILURE;
michael@0 135 }
michael@0 136 }
michael@0 137
michael@0 138 if (!mSocketWidget) {
michael@0 139 return NS_ERROR_FAILURE;
michael@0 140 }
michael@0 141
michael@0 142 // Make sure to resize and re-place the window if required.
michael@0 143 SetAllocation();
michael@0 144 // Need to reset "window" each time as nsObjectFrame::DidReflow sets it
michael@0 145 // to the ancestor window.
michael@0 146 #if (MOZ_WIDGET_GTK == 2)
michael@0 147 if (GTK_IS_XTBIN(mSocketWidget)) {
michael@0 148 // Point the NPWindow structures window to the actual X window
michael@0 149 SetWindow(GTK_XTBIN(mSocketWidget)->xtwindow);
michael@0 150 }
michael@0 151 else { // XEmbed or OOP&Xt
michael@0 152 SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget)));
michael@0 153 }
michael@0 154 #else
michael@0 155 // Gtk3 supports only OOP by GtkSocket
michael@0 156 SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget)));
michael@0 157 #endif
michael@0 158
michael@0 159 #ifdef DEBUG
michael@0 160 printf("nsPluginNativeWindowGtk: call SetWindow with xid=%p\n", (void *)window);
michael@0 161 #endif
michael@0 162 } // NPWindowTypeWindow
michael@0 163 aPluginInstance->SetWindow(this);
michael@0 164 }
michael@0 165 else if (mPluginInstance)
michael@0 166 mPluginInstance->SetWindow(nullptr);
michael@0 167
michael@0 168 SetPluginInstance(aPluginInstance);
michael@0 169 return NS_OK;
michael@0 170 }
michael@0 171
michael@0 172 nsresult nsPluginNativeWindowGtk::CreateXEmbedWindow(bool aEnableXtFocus) {
michael@0 173 NS_ASSERTION(!mSocketWidget,"Already created a socket widget!");
michael@0 174 GdkDisplay *display = gdk_display_get_default();
michael@0 175 GdkWindow *parent_win = gdk_x11_window_lookup_for_display(display, GetWindow());
michael@0 176 mSocketWidget = gtk_socket_new();
michael@0 177
michael@0 178 //attach the socket to the container widget
michael@0 179 gtk_widget_set_parent_window(mSocketWidget, parent_win);
michael@0 180
michael@0 181 // enable/disable focus event handlers,
michael@0 182 // see plugin_window_filter_func() for details
michael@0 183 g_object_set_data(G_OBJECT(mSocketWidget), "enable-xt-focus", (void *)aEnableXtFocus);
michael@0 184
michael@0 185 // Make sure to handle the plug_removed signal. If we don't the
michael@0 186 // socket will automatically be destroyed when the plug is
michael@0 187 // removed, which means we're destroying it more than once.
michael@0 188 // SYNTAX ERROR.
michael@0 189 g_signal_connect(mSocketWidget, "plug_removed",
michael@0 190 G_CALLBACK(plug_removed_cb), nullptr);
michael@0 191
michael@0 192 g_signal_connect(mSocketWidget, "unrealize",
michael@0 193 G_CALLBACK(socket_unrealize_cb), nullptr);
michael@0 194
michael@0 195 g_signal_connect(mSocketWidget, "destroy",
michael@0 196 G_CALLBACK(gtk_widget_destroyed), &mSocketWidget);
michael@0 197
michael@0 198 gpointer user_data = nullptr;
michael@0 199 gdk_window_get_user_data(parent_win, &user_data);
michael@0 200
michael@0 201 GtkContainer *container = GTK_CONTAINER(user_data);
michael@0 202 gtk_container_add(container, mSocketWidget);
michael@0 203 gtk_widget_realize(mSocketWidget);
michael@0 204
michael@0 205 // The GtkSocket has a visible window, but the plugin's XEmbed plug will
michael@0 206 // cover this window. Normally GtkSockets let the X server paint their
michael@0 207 // background and this would happen immediately (before the plug is
michael@0 208 // created). Setting the background to None prevents the server from
michael@0 209 // painting this window, avoiding flicker.
michael@0 210 // TODO GTK3
michael@0 211 #if (MOZ_WIDGET_GTK == 2)
michael@0 212 gdk_window_set_back_pixmap(gtk_widget_get_window(mSocketWidget), nullptr, FALSE);
michael@0 213 #endif
michael@0 214
michael@0 215 // Resize before we show
michael@0 216 SetAllocation();
michael@0 217
michael@0 218 gtk_widget_show(mSocketWidget);
michael@0 219
michael@0 220 gdk_flush();
michael@0 221 SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget)));
michael@0 222
michael@0 223 // Fill out the ws_info structure.
michael@0 224 // (The windowless case is done in nsObjectFrame.cpp.)
michael@0 225 GdkWindow *gdkWindow = gdk_x11_window_lookup_for_display(display, GetWindow());
michael@0 226 if(!gdkWindow)
michael@0 227 return NS_ERROR_FAILURE;
michael@0 228
michael@0 229 mWsInfo.display = GDK_WINDOW_XDISPLAY(gdkWindow);
michael@0 230 #if (MOZ_WIDGET_GTK == 2)
michael@0 231 mWsInfo.colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gdkWindow));
michael@0 232 GdkVisual* gdkVisual = gdk_drawable_get_visual(gdkWindow);
michael@0 233 mWsInfo.depth = gdkVisual->depth;
michael@0 234 #else
michael@0 235 mWsInfo.colormap = None;
michael@0 236 GdkVisual* gdkVisual = gdk_window_get_visual(gdkWindow);
michael@0 237 mWsInfo.depth = gdk_visual_get_depth(gdkVisual);
michael@0 238 #endif
michael@0 239 mWsInfo.visual = GDK_VISUAL_XVISUAL(gdkVisual);
michael@0 240
michael@0 241 return NS_OK;
michael@0 242 }
michael@0 243
michael@0 244 void nsPluginNativeWindowGtk::SetAllocation() {
michael@0 245 if (!mSocketWidget)
michael@0 246 return;
michael@0 247
michael@0 248 GtkAllocation new_allocation;
michael@0 249 new_allocation.x = 0;
michael@0 250 new_allocation.y = 0;
michael@0 251 new_allocation.width = width;
michael@0 252 new_allocation.height = height;
michael@0 253 gtk_widget_size_allocate(mSocketWidget, &new_allocation);
michael@0 254 }
michael@0 255
michael@0 256 #if (MOZ_WIDGET_GTK == 2)
michael@0 257 nsresult nsPluginNativeWindowGtk::CreateXtWindow() {
michael@0 258 NS_ASSERTION(!mSocketWidget,"Already created a socket widget!");
michael@0 259
michael@0 260 #ifdef DEBUG
michael@0 261 printf("About to create new xtbin of %i X %i from %p...\n",
michael@0 262 width, height, (void*)window);
michael@0 263 #endif
michael@0 264 GdkDisplay *display = gdk_display_get_default();
michael@0 265 GdkWindow *gdkWindow = gdk_x11_window_lookup_for_display(display, GetWindow());
michael@0 266 mSocketWidget = gtk_xtbin_new(gdkWindow, 0);
michael@0 267 // Check to see if creating the xtbin failed for some reason.
michael@0 268 // if it did, we can't go any further.
michael@0 269 if (!mSocketWidget)
michael@0 270 return NS_ERROR_FAILURE;
michael@0 271
michael@0 272 g_signal_connect(mSocketWidget, "destroy",
michael@0 273 G_CALLBACK(gtk_widget_destroyed), &mSocketWidget);
michael@0 274
michael@0 275 gtk_widget_set_size_request(mSocketWidget, width, height);
michael@0 276
michael@0 277 #ifdef DEBUG
michael@0 278 printf("About to show xtbin(%p)...\n", (void*)mSocketWidget); fflush(nullptr);
michael@0 279 #endif
michael@0 280 gtk_widget_show(mSocketWidget);
michael@0 281 #ifdef DEBUG
michael@0 282 printf("completed gtk_widget_show(%p)\n", (void*)mSocketWidget); fflush(nullptr);
michael@0 283 #endif
michael@0 284
michael@0 285 // Fill out the ws_info structure.
michael@0 286 GtkXtBin* xtbin = GTK_XTBIN(mSocketWidget);
michael@0 287 // The xtbin has its own Display structure.
michael@0 288 mWsInfo.display = xtbin->xtdisplay;
michael@0 289 mWsInfo.colormap = xtbin->xtclient.xtcolormap;
michael@0 290 mWsInfo.visual = xtbin->xtclient.xtvisual;
michael@0 291 mWsInfo.depth = xtbin->xtclient.xtdepth;
michael@0 292 // Leave mWsInfo.type = 0 - Who knows what this is meant to be?
michael@0 293
michael@0 294 XFlush(mWsInfo.display);
michael@0 295
michael@0 296 return NS_OK;
michael@0 297 }
michael@0 298 #endif
michael@0 299
michael@0 300 /* static */
michael@0 301 gboolean
michael@0 302 plug_removed_cb (GtkWidget *widget, gpointer data)
michael@0 303 {
michael@0 304 // Gee, thanks for the info!
michael@0 305 return TRUE;
michael@0 306 }
michael@0 307
michael@0 308 static void
michael@0 309 socket_unrealize_cb(GtkWidget *widget, gpointer data)
michael@0 310 {
michael@0 311 // Unmap and reparent any child windows that GDK does not yet know about.
michael@0 312 // (See bug 540114 comment 10.)
michael@0 313 GdkWindow* socket_window = gtk_widget_get_window(widget);
michael@0 314 GdkDisplay* gdkDisplay = gdk_display_get_default();
michael@0 315 Display* display = GDK_DISPLAY_XDISPLAY(gdkDisplay);
michael@0 316
michael@0 317 // Ignore X errors that may happen if windows get destroyed (possibly
michael@0 318 // requested by the plugin) between XQueryTree and when we operate on them.
michael@0 319 gdk_error_trap_push();
michael@0 320
michael@0 321 Window root, parent;
michael@0 322 Window* children;
michael@0 323 unsigned int nchildren;
michael@0 324 if (!XQueryTree(display, gdk_x11_window_get_xid(socket_window),
michael@0 325 &root, &parent, &children, &nchildren))
michael@0 326 return;
michael@0 327
michael@0 328 for (unsigned int i = 0; i < nchildren; ++i) {
michael@0 329 Window child = children[i];
michael@0 330 if (!gdk_x11_window_lookup_for_display(gdkDisplay, child)) {
michael@0 331 // This window is not known to GDK.
michael@0 332 XUnmapWindow(display, child);
michael@0 333 XReparentWindow(display, child, DefaultRootWindow(display), 0, 0);
michael@0 334 }
michael@0 335 }
michael@0 336
michael@0 337 if (children) XFree(children);
michael@0 338
michael@0 339 mozilla::FinishX(display);
michael@0 340 gdk_error_trap_pop();
michael@0 341 }

mercurial