dom/plugins/base/nsPluginNativeWindowGtk.cpp

changeset 0
6474c204b198
     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 +}

mercurial