1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is mozilla.org code.
19 * The Initial Developer of the Original Code is
20 * Sun Microsystems, Inc.
21 * Portions created by the Initial Developer are Copyright (C) 2003
22 * the Initial Developer. All Rights Reserved.
25 * Robin Lu <robin.lu@sun.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * This file is the Gtk2 implementation of plugin native window.
46 #include "nsPluginNativeWindow.h"
52 #ifdef MOZ_PLATFORM_HILDON
53 #define MOZ_COMPOSITED_PLUGINS
56 #ifdef MOZ_COMPOSITED_PLUGINS
58 #include <X11/extensions/Xdamage.h>
59 #include <X11/extensions/Xcomposite.h>
63 #include "gtk2xtbin.h"
66 #include "nsIPlugin.h"
67 #include "nsIPluginHost.h"
69 static NS_DEFINE_CID(kPluginManagerCID
, NS_PLUGINMANAGER_CID
);
72 class nsPluginNativeWindowGtk2
: public nsPluginNativeWindow
{
74 nsPluginNativeWindowGtk2();
75 virtual ~nsPluginNativeWindowGtk2();
77 virtual nsresult
CallSetWindow(nsCOMPtr
<nsIPluginInstance
> &aPluginInstance
);
79 NPSetWindowCallbackStruct mWsInfo
;
81 * Either a GtkSocket or a special GtkXtBin widget (derived from GtkSocket)
82 * that encapsulates the Xt toolkit within a Gtk Application.
84 GtkWidget
* mSocketWidget
;
85 nsresult
CreateXEmbedWindow();
86 nsresult
CreateXtWindow();
88 PRBool
CanGetValueFromPlugin(nsCOMPtr
<nsIPluginInstance
> &aPluginInstance
);
89 #ifdef MOZ_COMPOSITED_PLUGINS
90 nsresult
CreateXCompositedWindow();
91 static GdkFilterReturn
plugin_composite_filter_func (GdkXEvent
*xevent
,
96 GtkWidget
* mParentWindow
;
100 static gboolean
plug_removed_cb (GtkWidget
*widget
, gpointer data
);
102 nsPluginNativeWindowGtk2::nsPluginNativeWindowGtk2() : nsPluginNativeWindow()
104 // initialize the struct fields
110 memset(&clipRect
, 0, sizeof(clipRect
));
112 type
= nsPluginWindowType_Window
;
115 mWsInfo
.display
= nsnull
;
116 mWsInfo
.visual
= nsnull
;
117 mWsInfo
.colormap
= 0;
119 #ifdef MOZ_COMPOSITED_PLUGINS
125 nsPluginNativeWindowGtk2::~nsPluginNativeWindowGtk2()
128 gtk_widget_destroy(mSocketWidget
);
131 #ifdef MOZ_COMPOSITED_PLUGINS
133 gtk_widget_destroy(mParentWindow
);
137 gdk_window_remove_filter (nsnull
, plugin_composite_filter_func
, this);
142 nsresult
PLUG_NewPluginNativeWindow(nsPluginNativeWindow
** aPluginNativeWindow
)
144 NS_ENSURE_ARG_POINTER(aPluginNativeWindow
);
145 *aPluginNativeWindow
= new nsPluginNativeWindowGtk2();
146 return *aPluginNativeWindow
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
149 nsresult
PLUG_DeletePluginNativeWindow(nsPluginNativeWindow
* aPluginNativeWindow
)
151 NS_ENSURE_ARG_POINTER(aPluginNativeWindow
);
152 nsPluginNativeWindowGtk2
*p
= (nsPluginNativeWindowGtk2
*)aPluginNativeWindow
;
157 #ifdef MOZ_COMPOSITED_PLUGINS
158 /* the base xdamage event number.*/
159 static int xdamage_event_base
;
162 nsPluginNativeWindowGtk2::plugin_composite_filter_func (GdkXEvent
*xevent
,
166 nsPluginNativeWindowGtk2
*native_window
= (nsPluginNativeWindowGtk2
*)data
;
167 XDamageNotifyEvent
*ev
;
169 ev
= (XDamageNotifyEvent
*) xevent
;
170 if (ev
->type
!= xdamage_event_base
+ XDamageNotify
)
171 return GDK_FILTER_CONTINUE
;
173 //printf("Damage event %d %d %d %d\n",ev->area.x, ev->area.y, ev->area.width, ev->area.height);
174 parts
= XFixesCreateRegion (GDK_DISPLAY(), 0, 0);
175 XDamageSubtract (GDK_DISPLAY(), native_window
->mDamage
, None
, parts
);
177 /* We try to do our area invalidation here */
179 rect
.top
= ev
->area
.x
;
180 rect
.left
= ev
->area
.y
;
181 rect
.right
= ev
->area
.x
+ ev
->area
.width
;
182 rect
.bottom
= ev
->area
.y
+ ev
->area
.height
;
184 /* There might be a better way to do this? */
185 if (native_window
->mPluginInstance
) {
186 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
187 if (NS_SUCCEEDED(native_window
->mPluginInstance
->GetPeer(getter_AddRefs(peer
))) && peer
) {
188 nsCOMPtr
<nsIWindowlessPluginInstancePeer
> wpeer(do_QueryInterface(peer
));
190 // XXX nsRect & NPRect are structurally equivalent
191 wpeer
->InvalidateRect(&rect
);
196 return GDK_FILTER_REMOVE
;
200 nsresult
nsPluginNativeWindowGtk2::CallSetWindow(nsCOMPtr
<nsIPluginInstance
> &aPluginInstance
)
202 if(aPluginInstance
) {
203 if (type
== nsPluginWindowType_Window
) {
206 PRBool needXEmbed
= PR_FALSE
;
207 if (CanGetValueFromPlugin(aPluginInstance
)) {
208 rv
= aPluginInstance
->GetValue
209 ((nsPluginInstanceVariable
)NPPVpluginNeedsXEmbed
, &needXEmbed
);
211 printf("nsPluginNativeWindowGtk2: NPPVpluginNeedsXEmbed=%d\n", needXEmbed
);
215 #ifdef MOZ_COMPOSITED_PLUGINS
216 CreateXCompositedWindow();
218 CreateXEmbedWindow();
227 return NS_ERROR_FAILURE
;
229 // Make sure to resize and re-place the window if required.
230 // Need to reset "window" each time as nsObjectFrame::DidReflow sets it
231 // to the ancestor window.
232 if(GTK_IS_XTBIN(mSocketWidget
)) {
233 gtk_xtbin_resize(mSocketWidget
, width
, height
);
234 // Point the NPWindow structures window to the actual X window
235 window
= (nsPluginPort
*)GTK_XTBIN(mSocketWidget
)->xtwindow
;
239 window
= (nsPluginPort
*)gtk_socket_get_id(GTK_SOCKET(mSocketWidget
));
242 printf("nsPluginNativeWindowGtk2: call SetWindow with xid=%p\n", (void *)window
);
244 } // nsPluginWindowType_Window
245 aPluginInstance
->SetWindow(this);
247 else if (mPluginInstance
)
248 mPluginInstance
->SetWindow(nsnull
);
250 SetPluginInstance(aPluginInstance
);
254 nsresult
nsPluginNativeWindowGtk2::CreateXEmbedWindow() {
255 NS_ASSERTION(!mSocketWidget
,"Already created a socket widget!");
257 GdkWindow
*parent_win
= gdk_window_lookup((XID
)window
);
258 mSocketWidget
= gtk_socket_new();
260 //attach the socket to the container widget
261 gtk_widget_set_parent_window(mSocketWidget
, parent_win
);
263 // Make sure to handle the plug_removed signal. If we don't the
264 // socket will automatically be destroyed when the plug is
265 // removed, which means we're destroying it more than once.
267 g_signal_connect(mSocketWidget
, "plug_removed",
268 G_CALLBACK(plug_removed_cb
), NULL
);
270 g_signal_connect(mSocketWidget
, "destroy",
271 G_CALLBACK(gtk_widget_destroyed
), &mSocketWidget
);
273 gpointer user_data
= NULL
;
274 gdk_window_get_user_data(parent_win
, &user_data
);
276 GtkContainer
*container
= GTK_CONTAINER(user_data
);
277 gtk_container_add(container
, mSocketWidget
);
278 gtk_widget_realize(mSocketWidget
);
280 // Resize before we show
283 gtk_widget_show(mSocketWidget
);
286 window
= (nsPluginPort
*)gtk_socket_get_id(GTK_SOCKET(mSocketWidget
));
288 // Fill out the ws_info structure.
289 // (The windowless case is done in nsObjectFrame.cpp.)
290 GdkWindow
*gdkWindow
= gdk_window_lookup((XID
)window
);
291 mWsInfo
.display
= GDK_WINDOW_XDISPLAY(gdkWindow
);
292 mWsInfo
.colormap
= GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gdkWindow
));
293 GdkVisual
* gdkVisual
= gdk_drawable_get_visual(gdkWindow
);
294 mWsInfo
.visual
= GDK_VISUAL_XVISUAL(gdkVisual
);
295 mWsInfo
.depth
= gdkVisual
->depth
;
300 #ifdef MOZ_COMPOSITED_PLUGINS
302 nsresult
nsPluginNativeWindowGtk2::CreateXCompositedWindow() {
303 NS_ASSERTION(!mSocketWidget
,"Already created a socket widget!");
305 mParentWindow
= gtk_window_new(GTK_WINDOW_POPUP
);
306 mSocketWidget
= gtk_socket_new();
307 GdkWindow
*parent_win
= mParentWindow
->window
;
309 //attach the socket to the container widget
310 gtk_widget_set_parent_window(mSocketWidget
, parent_win
);
312 // Make sure to handle the plug_removed signal. If we don't the
313 // socket will automatically be destroyed when the plug is
314 // removed, which means we're destroying it more than once.
316 g_signal_connect(mSocketWidget
, "plug_removed",
317 G_CALLBACK(plug_removed_cb
), NULL
);
319 g_signal_connect(mSocketWidget
, "destroy",
320 G_CALLBACK(gtk_widget_destroyed
), &mSocketWidget
);
322 /*gpointer user_data = NULL;
323 gdk_window_get_user_data(parent_win, &user_data);
325 GtkContainer
*container
= GTK_CONTAINER(mParentWindow
);
326 gtk_container_add(container
, mSocketWidget
);
327 gtk_widget_realize(mSocketWidget
);
329 // Resize before we show
331 gtk_widget_set_size_request (mSocketWidget
, width
, height
);
333 gtk_window_move (GTK_WINDOW(mParentWindow
), width
+1000, height
+1000);
336 gtk_widget_show(mSocketWidget
);
337 gtk_widget_show_all(mParentWindow
);
339 /* store away a reference to the socketwidget */
340 mPlugWindow
= (mSocketWidget
);
343 window
= (nsPluginPort
*)gtk_socket_get_id(GTK_SOCKET(mSocketWidget
));
345 /* This is useful if we still have the plugin window inline
346 * i.e. firefox vs. fennec */
347 // gdk_window_set_composited(mSocketWidget->window, TRUE);
350 /* we install a general handler instead of one specific to a particular window
351 * because we don't have a GdkWindow for the plugin window */
352 gdk_window_add_filter (parent_win
, plugin_composite_filter_func
, this);
355 if (!XDamageQueryExtension (GDK_DISPLAY (), &xdamage_event_base
, &junk
))
356 printf ("This requires the XDamage extension");
358 mDamage
= XDamageCreate(GDK_DISPLAY(), (Drawable
)window
, XDamageReportNonEmpty
);
359 XCompositeRedirectWindow (GDK_DISPLAY(),
361 CompositeRedirectManual
);
363 /* this is a hack to avoid having flash causing a crash when it is unloaded.
364 * libplayback sets up dbus_connection_filters. When flash is unloaded it takes
365 * libplayback with it, however the connection filters are not removed
366 * which causes a crash when dbus tries to execute them. dlopening libplayback
367 * ensures that those functions stay around even after flash is gone. */
368 static void *libplayback_handle
;
369 if (!libplayback_handle
) {
370 libplayback_handle
= dlopen("libplayback-1.so.0", RTLD_NOW
);
375 // Fill out the ws_info structure.
376 // (The windowless case is done in nsObjectFrame.cpp.)
377 GdkWindow
*gdkWindow
= gdk_window_lookup((XID
)window
);
378 mWsInfo
.display
= GDK_WINDOW_XDISPLAY(gdkWindow
);
379 mWsInfo
.colormap
= GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gdkWindow
));
380 GdkVisual
* gdkVisual
= gdk_drawable_get_visual(gdkWindow
);
381 mWsInfo
.visual
= GDK_VISUAL_XVISUAL(gdkVisual
);
382 mWsInfo
.depth
= gdkVisual
->depth
;
388 void nsPluginNativeWindowGtk2::SetAllocation() {
392 GtkAllocation new_allocation
;
393 new_allocation
.x
= 0;
394 new_allocation
.y
= 0;
395 new_allocation
.width
= width
;
396 new_allocation
.height
= height
;
397 gtk_widget_size_allocate(mSocketWidget
, &new_allocation
);
400 nsresult
nsPluginNativeWindowGtk2::CreateXtWindow() {
401 NS_ASSERTION(!mSocketWidget
,"Already created a socket widget!");
404 printf("About to create new xtbin of %i X %i from %p...\n",
405 width
, height
, (void*)window
);
407 GdkWindow
*gdkWindow
= gdk_window_lookup((XID
)window
);
408 mSocketWidget
= gtk_xtbin_new(gdkWindow
, 0);
409 // Check to see if creating the xtbin failed for some reason.
410 // if it did, we can't go any further.
412 return NS_ERROR_FAILURE
;
414 gtk_widget_set_size_request(mSocketWidget
, width
, height
);
417 printf("About to show xtbin(%p)...\n", (void*)mSocketWidget
); fflush(NULL
);
419 gtk_widget_show(mSocketWidget
);
421 printf("completed gtk_widget_show(%p)\n", (void*)mSocketWidget
); fflush(NULL
);
424 // Fill out the ws_info structure.
425 GtkXtBin
* xtbin
= GTK_XTBIN(mSocketWidget
);
426 // The xtbin has its own Display structure.
427 mWsInfo
.display
= xtbin
->xtdisplay
;
428 mWsInfo
.colormap
= xtbin
->xtclient
.xtcolormap
;
429 mWsInfo
.visual
= xtbin
->xtclient
.xtvisual
;
430 mWsInfo
.depth
= xtbin
->xtclient
.xtdepth
;
431 // Leave mWsInfo.type = 0 - Who knows what this is meant to be?
433 XFlush(mWsInfo
.display
);
438 PRBool
nsPluginNativeWindowGtk2::CanGetValueFromPlugin(nsCOMPtr
<nsIPluginInstance
> &aPluginInstance
)
441 if(aPluginInstance
) {
443 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
445 rv
= aPluginInstance
->GetPeer(getter_AddRefs(peer
));
446 if (NS_SUCCEEDED(rv
) && peer
) {
447 const char *aMimeType
= nsnull
;
449 peer
->GetMIMEType((nsMIMEType
*)&aMimeType
);
451 (PL_strncasecmp(aMimeType
, "application/x-java-vm", 21) == 0 ||
452 PL_strncasecmp(aMimeType
, "application/x-java-applet", 25) == 0)) {
453 nsCOMPtr
<nsIPluginHost
> pluginHost
= do_GetService(kPluginManagerCID
, &rv
);
454 if (NS_SUCCEEDED(rv
) && pluginHost
) {
455 nsIPlugin
* pluginFactory
= NULL
;
457 rv
= pluginHost
->GetPluginFactory("application/x-java-vm", &pluginFactory
);
458 if (NS_SUCCEEDED(rv
) && pluginFactory
) {
459 const char * jpiDescription
= NULL
;
461 pluginFactory
->GetValue(nsPluginVariable_DescriptionString
, (void*)&jpiDescription
);
466 * "Java(TM) Plug-in" is Sun's Java Plugin Trademark,
467 * so we are sure that this is Sun 's Java Plugin if
468 * the description start with "Java(TM) Plug-in"
470 if (PL_strncasecmp(jpiDescription
, "Java(TM) Plug-in", 16) == 0) {
471 // Java Plugin support Xembed from JRE 1.5
472 if (PL_strcasecmp(jpiDescription
+ 17, "1.5") < 0)
475 if (PL_strncasecmp(jpiDescription
, "<a href=\"http://www.blackdown.org/java-linux.html\">", 51) == 0) {
476 // Java Plugin support Xembed from JRE 1.5
477 if (PL_strcasecmp(jpiDescription
+ 92, "1.5") < 0)
480 if (PL_strncasecmp(jpiDescription
, "IBM Java(TM) Plug-in", 20) == 0) {
481 // Java Plugin support Xembed from JRE 1.5
482 if (PL_strcasecmp(jpiDescription
+ 27, "1.5") < 0)
497 plug_removed_cb (GtkWidget
*widget
, gpointer data
)
499 // Gee, thanks for the info!