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

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

mercurial