automatically merged revision 768870:

- Make the XEmbed host embed directly, removing 2 layers of embedding,
upon suggestion of Seli, hopefully making things more robust
- Be more careful in initializing the plugin, to avoid extra NPSetWindow calls
- Workaround Qt bug in the Xt host, to avoid annoying flicker of an unembedded

svn path=/trunk/KDE/kdebase/apps/; revision=768878
This commit is contained in:
Maks Orlovich 2008-01-30 20:51:18 +00:00
parent d34ed57efe
commit 3980953c02
10 changed files with 150 additions and 184 deletions

View file

@ -45,6 +45,7 @@
#include <QtGui/QX11EmbedContainer>
#include <QTextStream>
#include <QRegExp>
#include <QTimer>
#include "nsplugins_class_interface.h"
#include "nsplugins_instance_interface.h"
@ -52,6 +53,8 @@
#include <config-apps.h>
#include <X11/Xlib.h>
NSPluginLoader *NSPluginLoader::s_instance = 0;
int NSPluginLoader::s_refCount = 0;
@ -59,10 +62,14 @@ int NSPluginLoader::s_refCount = 0;
NSPluginInstance::NSPluginInstance(QWidget *parent, const QString& viewerDBusId, const QString& id)
: EMBEDCLASS(parent)
{
setWindowTitle("nsp.host"); // for debugging..
_instanceInterface = new org::kde::nsplugins::Instance( viewerDBusId, id, QDBusConnection::sessionBus() );
_loader = 0;
shown = false;
shown = false;
embedded = false;
resizedAfterShow = false;
QGridLayout *_layout = new QGridLayout(this);
_layout->setMargin(1);
_layout->setSpacing(1);
@ -85,12 +92,6 @@ void NSPluginInstance::doLoadPlugin() {
delete _button;
_button = 0L;
_loader = NSPluginLoader::instance();
kDebug() << _instanceInterface->winId();
embedClient( _instanceInterface->winId() );
show();
shown = true;
}
}
@ -114,16 +115,46 @@ void NSPluginInstance::windowChanged(WId w)
}
/*
Flash 9.0r115 is picky, and only wants to be sized once,
so we want to do it when we're ready. For that, we wait
until we get the 2nd resize from khtml (and not the original
Qt default)
*/
void NSPluginInstance::resizeEvent(QResizeEvent *event)
{
kDebug() << "NSPluginInstance(client)::resizeEvent" << shown << event->size();
if (shown == false)
return;
EMBEDCLASS::resizeEvent(event);
if (isVisible()) {
_instanceInterface->resizePlugin(width(), height());
}
kDebug() << "NSPluginInstance(client)::resizeEvent";
if (shown)
resizedAfterShow = true;
kDebug() << this << shown << resizedAfterShow;
EMBEDCLASS::resizeEvent(event);
QTimer::singleShot(10, this, SLOT(embedIfNeeded()));
}
void NSPluginInstance::showEvent(QShowEvent *event)
{
shown = true;
kDebug() << this << shown << resizedAfterShow;
EMBEDCLASS::showEvent(event);
QTimer::singleShot(10, this, SLOT(embedIfNeeded()));
}
void NSPluginInstance::embedIfNeeded()
{
if (embedded)
return;
if (shown && resizedAfterShow) {
kDebug() << isVisible() << width() << height() << winId() << internalWinId();
show();
qApp->syncX();
embedded = true;
_instanceInterface->setupWindow(winId(), width(), height());
qApp->syncX();
}
}
void NSPluginInstance::javascriptResult(int id, const QString &result)
@ -391,7 +422,7 @@ NSPluginInstance *NSPluginLoader::newInstance(QWidget *parent, const QString& ur
return 0;
}
}
kDebug() << "-> ownID" << ownDBusId << " viewer ID:" << _viewerDBusId;
QStringList argn( _argn );
@ -426,7 +457,7 @@ NSPluginInstance *NSPluginLoader::newInstance(QWidget *parent, const QString& ur
kDebug() << "Couldn't create plugin class";
return 0;
}
org::kde::nsplugins::Class* cls = new org::kde::nsplugins::Class( _viewerDBusId, cls_ref.path(), QDBusConnection::sessionBus() );
// handle special plugin cases

View file

@ -58,9 +58,10 @@ public:
private Q_SLOTS:
void doLoadPlugin();
void embedIfNeeded();
protected:
void resizeEvent(QResizeEvent *event);
void showEvent(QShowEvent *event);
void windowChanged(WId w);
virtual void focusInEvent( QFocusEvent* event );
virtual void focusOutEvent( QFocusEvent* event );
@ -68,6 +69,8 @@ private:
class NSPluginLoader *_loader;
OrgKdeNspluginsInstanceInterface *_instanceInterface;
bool shown;
bool embedded; // if embedding was complete
bool resizedAfterShow;
QPushButton *_button;
QGridLayout *_layout;
};

View file

@ -192,7 +192,7 @@ NPError g_NPN_GetValue(NPP /*instance*/, NPNVariable variable, void *value)
case NPNVToolkit:
// This is messy. OSS things want to see "Gtk2" here;
// but commercial flash works better if we return something else.
// So we return a KHTML classic, since we can work with
// So we return a KHTML classic, since we can work with
// the community members far easier.
*(NPNToolkitType*)value = (NPNToolkitType)0xFEEDABEE;
return NPERR_NO_ERROR;
@ -593,7 +593,7 @@ NPError g_NPN_SetValue(NPP /*instance*/, NPPVariable variable, void* /*value*/)
static int s_instanceCounter = 0;
NSPluginInstance::NSPluginInstance(NPP privateData, NPPluginFuncs *pluginFuncs,
KLibrary *handle, int width, int height,
KLibrary *handle,
const QString &src, const QString &/*mime*/,
const QString &appId, const QString &callbackId,
bool embed,
@ -606,14 +606,11 @@ NSPluginInstance::NSPluginInstance(NPP privateData, NPPluginFuncs *pluginFuncs,
QDBusConnection::sessionBus().registerObject( objectName(), this );
Q_UNUSED(embed);
_firstResize = true;
_embedded = false;
_npp = privateData;
_npp->ndata = this;
_destroyed = false;
_handle = handle;
_width = width;
_height = height;
_tempFiles.setAutoDelete( true );
_streams.setAutoDelete( true );
_waitingRequests.setAutoDelete( true );
@ -632,33 +629,18 @@ NSPluginInstance::NSPluginInstance(NPP privateData, NPPluginFuncs *pluginFuncs,
kDebug(1431) << "pdata = " << _npp->pdata;
kDebug(1431) << "ndata = " << _npp->ndata;
if (width == 0)
width = 1600;
if (height == 0)
height = 1200;
// Create our XEmbed peer with the part.
_outside = new QX11EmbedWidget();
_outside->hide();
_outside->setWindowTitle("nspluginviewer.outside");
// We need to wait until we're embedded before being able to
// do things.
connect(_outside, SIGNAL(embedded()), this, SLOT(embeddedIntoHost()));
// Create the appropriate host for the plugin type.
_pluginHost = 0;
int result = PR_FALSE;
//### iceweasel does something odd here --- it enabled XEmbed for swfdec,
// even though that doesn't provide GetValue at all(!)
if (NPGetValue(NPPVpluginNeedsXEmbed, &result) == NPERR_NO_ERROR && result) {
kDebug(1431) << "plugin reqests XEmbed";
_pluginHost = new PluginHostXEmbed(this, _outside);
_pluginHost = new PluginHostXEmbed(this);
} else {
kDebug(1431) << "plugin requests Xt";
_pluginHost = new PluginHostXt(this, _outside, width, height);
_pluginHost = new PluginHostXt(this);
}
XSync(QX11Info::display(), false);
@ -714,9 +696,6 @@ void NSPluginInstance::destroy()
delete _pluginHost;
_pluginHost = 0;
delete _outside;
_outside = 0;
if (_npp) {
::free(_npp); // matched with malloc() in newInstance
@ -831,7 +810,7 @@ void NSPluginInstance::timer()
QString NSPluginInstance::normalizedURL(const QString& url) const {
// ### for dfaure: KUrl(KUrl("http://www.youtube.com/?v=JvOSnRD5aNk"), KUrl("javascript:window.location+"__flashplugin_unique__"));
//### hack, prolly evil, etc.
if (url.startsWith("javascript:"))
return url;
@ -909,45 +888,16 @@ void NSPluginInstance::streamFinished( NSPluginStreamBase* strm )
_timer->start( 100 );
}
void NSPluginInstance::embeddedIntoHost()
{
_outside->show();
setupWindow();
_embedded = true;
}
void NSPluginInstance::setupWindow()
void NSPluginInstance::setupWindow(int winId, int w, int h)
{
kDebug(1431) << "-> NSPluginInstance::setupWindow( winid =" << winId << " w=" << w << ", h=" << h << " ) ";
if (_pluginHost)
_pluginHost->setupWindow(_width, _height);
}
void NSPluginInstance::resizePlugin(int w, int h)
{
kDebug(1431) << "-> NSPluginInstance::resizePlugin( w=" << w << ", h=" << h << " ) ";
if (!_embedded) {
_width = w;
_height = h;
return;
}
if (w == _width && h == _height)
return;
_width = w;
_height = h;
_outside->resize(w, h);
if (_pluginHost)
_pluginHost->resizePlugin(w, h);
if (_firstResize) {
_firstResize = false;
setupWindow();
}
_pluginHost->setupWindow(winId, w, h);
else
kWarning(1431) << "No plugin host!";
kDebug(1431) << "<- NSPluginInstance::resizePlugin";
_embedded = true;
}
@ -1292,7 +1242,7 @@ NSPluginClass::NSPluginClass( const QString &library,
// initialize plugin
kDebug(1431) << "Plugin library " << library << " loaded!";
// see if it uses gtk
if (!s_initedGTK) {
gtkInitFunc* gtkInit = (gtkInitFunc*)_handle->resolveFunction("gtk_init");
@ -1302,7 +1252,7 @@ NSPluginClass::NSPluginClass( const QString &library,
s_initedGTK = true;
}
}
_constructed = true;
_error = initialize()!=NPERR_NO_ERROR;
}
@ -1338,7 +1288,7 @@ int NSPluginClass::initialize()
// initialize nescape exported functions
memset(&_pluginFuncs, 0, sizeof(_pluginFuncs));
memset(&_nsFuncs, 0, sizeof(_nsFuncs));
_pluginFuncs.size = sizeof(_pluginFuncs);
_nsFuncs.size = sizeof(_nsFuncs);
_nsFuncs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
@ -1399,8 +1349,6 @@ QDBusObjectPath NSPluginClass::newInstance( const QString &url, const QString &m
char **_argn = new char*[argc];
char **_argv = new char*[argc];
QString src = url;
int width = 0;
int height = 0;
QString baseURL = url;
for (unsigned int i=0; i<argc; i++)
@ -1414,8 +1362,6 @@ QDBusObjectPath NSPluginClass::newInstance( const QString &url, const QString &m
_argn[i] = strdup(n);
_argv[i] = strdup(v);
if (!strcasecmp(_argn[i], "WIDTH")) width = argv[i].toInt();
if (!strcasecmp(_argn[i], "HEIGHT")) height = argv[i].toInt();
if (!strcasecmp(_argn[i], "__KHTML__PLUGINBASEURL")) baseURL = _argv[i];
kDebug(1431) << "argn=" << _argn[i] << " argv=" << _argv[i];
}
@ -1433,8 +1379,8 @@ QDBusObjectPath NSPluginClass::newInstance( const QString &url, const QString &m
// Create plugin instance object
NSPluginInstance *inst = new NSPluginInstance( npp, &_pluginFuncs, _handle,
width, height, baseURL, mimeType,
appId, callbackId, embed, this );
baseURL, mimeType, appId,
callbackId, embed, this );
// create plugin instance
NPError error = _pluginFuncs.newp(mime, npp, embed ? NP_EMBED : NP_FULL,

View file

@ -163,15 +163,14 @@ public:
// constructor, destructor
NSPluginInstance( NPP privateData, NPPluginFuncs *pluginFuncs, KLibrary *handle,
int width, int height, const QString &src, const QString &mime,
const QString &src, const QString &mime,
const QString &appId, const QString &callbackId, bool embed,
QObject *parent );
~NSPluginInstance();
// DBus-exported functions
void shutdown();
int winId() { return _outside->winId(); }
void resizePlugin(int w, int h);
void setupWindow(int winId, int w, int h);
void javascriptResult(int id, const QString &result);
void gotFocusIn();
void gotFocusOut();
@ -209,9 +208,7 @@ public:
public Q_SLOTS:
void streamFinished( NSPluginStreamBase *strm );
private Q_SLOTS:
void timer();
void embeddedIntoHost();
private:
friend class NSPluginStreamBase;
@ -220,8 +217,7 @@ private:
void setupWindow(); //Sets up our windows and registers it with the plugin.
bool _destroyed;
bool _visible;
bool _firstResize;
bool _embedded;
void addTempFile(KTemporaryFile *tmpFile);
Q3PtrList<KTemporaryFile> _tempFiles;
OrgKdeNspluginsCallBackInterface *_callback;
@ -231,14 +227,11 @@ private:
NPP _npp;
NPPluginFuncs _pluginFuncs;
QX11EmbedWidget* _outside; // What we get embedded into
bool _embedded; // Whether we've been embedded
PluginHost* _pluginHost; // Manages embedding of the plugin into us
Widget _area, _form, _toplevel;
QString _baseURL;
int _width, _height;
struct Request
{
@ -318,8 +311,8 @@ private:
QByteArray _app;
NPPluginFuncs _pluginFuncs;
NPNetscapeFuncs _nsFuncs;
// If plugins use gtk, we call the gtk_init function for them ---
// If plugins use gtk, we call the gtk_init function for them ---
// but only do it once.
static bool s_initedGTK;
};

View file

@ -3,10 +3,8 @@
<interface name="org.kde.nsplugins.Instance">
<method name="shutdown">
</method>
<method name="winId">
<arg type="i" direction="out"/>
</method>
<method name="resizePlugin">
<method name="setupWindow">
<arg name="winId" type="i" direction="in"/>
<arg name="w" type="i" direction="in"/>
<arg name="h" type="i" direction="in"/>
</method>

View file

@ -1,6 +1,6 @@
/*
This class abstracts away various ways one can embed plugins
This class abstracts away various ways one can embed plugins
Copyright (c) 2007 Maksim Orlovich <maksim@kde.org>
@ -29,10 +29,9 @@
class PluginHost
{
public:
virtual void setupWindow (int width, int height) = 0;
virtual void resizePlugin(int width, int height) = 0;
virtual void setupWindow (int winId, int width, int height) = 0;
virtual ~PluginHost() {};
void setupPluginWindow(NSPluginInstance* instance, void* winID, int width, int height);
};

View file

@ -28,49 +28,18 @@
#include <QVBoxLayout>
#include <QLabel>
PluginHostXEmbed::PluginHostXEmbed(NSPluginInstance* plugin, QX11EmbedWidget* outside):
_plugin(plugin), _outside(outside), _container(0)
{
// Nothing here yet --- will do once embedded, inside setupWindow
}
PluginHostXEmbed::PluginHostXEmbed(NSPluginInstance* plugin):
_plugin(plugin)
{}
PluginHostXEmbed::~PluginHostXEmbed()
{}
void PluginHostXEmbed::setupWindow(int winId, int width, int height)
{
/* delete _inside;
_inside = 0;*/
}
void PluginHostXEmbed::resizePlugin(int width, int height)
{
// return;
kDebug(1431) << _container->geometry() << _outside->geometry();
/* _inside->setGeometry(0, 0, width, height);*/
}
void PluginHostXEmbed::setupWindow(int width, int height)
{
if (!_container) {
QVBoxLayout* outsideLayout = new QVBoxLayout(_outside);
outsideLayout->setMargin(0);
_outside->setLayout(outsideLayout);
_container = new QX11EmbedContainer(_outside);
_container->setWindowTitle("_inner");
outsideLayout->addWidget(_container);
// QPalette p = _container->palette();
// p.setColor(_container->backgroundRole(), Qt::green);
// _container->setPalette(p);
// _container->setAutoFillBackground(true);
_container->show();
outsideLayout->update();
}
kDebug() << _outside->geometry() << _container->geometry() <<
_outside->isVisible() << _container->isVisible();
setupPluginWindow(_plugin, (void*)_container->winId(), width, height);
kDebug() << winId << width << height;
setupPluginWindow(_plugin, (void*)winId, width, height);
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -29,14 +29,11 @@
class PluginHostXEmbed : public PluginHost
{
public:
PluginHostXEmbed(NSPluginInstance* plugin, QX11EmbedWidget* outside);
virtual void setupWindow(int width, int height);
virtual void resizePlugin(int width, int height);
PluginHostXEmbed(NSPluginInstance* plugin);
virtual void setupWindow(int winId, int width, int height);
virtual ~PluginHostXEmbed();
private:
NSPluginInstance* _plugin;
QX11EmbedWidget* _outside;
QX11EmbedContainer* _container;
};

View file

@ -28,25 +28,54 @@
#include <QVBoxLayout>
#include <QLabel>
PluginHostXt::PluginHostXt(NSPluginInstance* plugin, QX11EmbedWidget* outside,
int width, int height):
_plugin(plugin), _outside(outside)
// BEGIN Workaround for QX11EmbedWidget silliness --- it maps widgets by default
// Most of the code is from Qt 4.3.3, Copyright (C) 1992-2007 Trolltech ASA
static unsigned int XEMBED_VERSION = 0;
static Atom _XEMBED_INFO = None;
static void initXEmbedAtoms(Display *d)
{
if (_XEMBED_INFO == None)
_XEMBED_INFO = XInternAtom(d, "_XEMBED_INFO", false);
}
static void doNotAskForXEmbedMapping(QX11EmbedWidget* widget)
{
initXEmbedAtoms(widget->x11Info().display());
unsigned int data[] = {XEMBED_VERSION, 0 /* e.g. not XEMBED_MAPPED*/};
XChangeProperty(widget->x11Info().display(), widget->winId(), _XEMBED_INFO,
_XEMBED_INFO, 32, PropModeReplace,
(unsigned char*) data, 2);
}
// END Workaround for QX11EmbedWidget silliness.
PluginHostXt::PluginHostXt(NSPluginInstance* plugin):
_plugin(plugin), _outside(0), _toplevel(0), _form(0)
{}
void PluginHostXt::setupWindow(int winId, int width, int height)
{
_outside = new QX11EmbedWidget();
doNotAskForXEmbedMapping(_outside);
_outside->embedInto(winId);
Arg args[7];
Cardinal nargs = 0;
XtSetArg(args[nargs], XtNwidth, width); nargs++;
XtSetArg(args[nargs], XtNheight, height); nargs++;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
String n, c;
XtGetApplicationNameAndClass(QX11Info::display(), &n, &c);
_toplevel = XtAppCreateShell("drawingArea", c, applicationShellWidgetClass,
QX11Info::display(), args, nargs);
//if (embed)
XtSetMappedWhenManaged(_toplevel, False);
XtRealizeWidget(_toplevel);
// Create form window that is searched for by flash plugin
_form = XtVaCreateWidget("form", compositeWidgetClass, _toplevel, NULL);
XtSetArg(args[nargs], XtNvisual, QX11Info::appVisual()); nargs++;
@ -66,24 +95,32 @@ PluginHostXt::PluginHostXt(NSPluginInstance* plugin, QX11EmbedWidget* outside,
#endif
XtRealizeWidget(_form);
XtManageChild(_form);
// Register forwarder
XtAddEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
False, forwarder, (XtPointer)this );
XtAddEventHandler(_form, (KeyPressMask|KeyReleaseMask),
False, forwarder, (XtPointer)this );
// Embed the Xt widget into the Qt widget
XReparentWindow(QX11Info::display(), XtWindow(_toplevel), _outside->winId(), 0, 0);
XtMapWidget(_toplevel);
setupPluginWindow(_plugin, (void*) XtWindow(_form), width, height);
}
PluginHostXt::~PluginHostXt()
{
XtRemoveEventHandler(_form, (KeyPressMask|KeyReleaseMask),
False, forwarder, (XtPointer)this);
XtRemoveEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
False, forwarder, (XtPointer)this);
XtDestroyWidget(_form);
XtDestroyWidget(_toplevel);
_form = 0;
_toplevel = 0;
if (_form) {
XtRemoveEventHandler(_form, (KeyPressMask|KeyReleaseMask),
False, forwarder, (XtPointer)this);
XtRemoveEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
False, forwarder, (XtPointer)this);
XtDestroyWidget(_form);
XtDestroyWidget(_toplevel);
_form = 0;
_toplevel = 0;
}
delete _outside;
}
void PluginHostXt::forwarder(Widget w, XtPointer cl_data, XEvent * event, Boolean * cont)
@ -112,14 +149,14 @@ static void resizeWidgets(Window w, int width, int height) {
}
}
#if 0
void PluginHostXt::resizePlugin(int w, int h)
{
kDebug(1431) << w << h;
XResizeWindow(QX11Info::display(), XtWindow(_form), w, h);
XResizeWindow(QX11Info::display(), XtWindow(_toplevel), w, h);
Arg args[7];
Cardinal nargs = 0;
XtSetArg(args[nargs], XtNwidth, w); nargs++;
@ -128,18 +165,12 @@ void PluginHostXt::resizePlugin(int w, int h)
XtSetArg(args[nargs], XtNdepth, QX11Info::appDepth()); nargs++;
XtSetArg(args[nargs], XtNcolormap, QX11Info::appColormap()); nargs++;
XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
XtSetValues(_form, args, nargs);
resizeWidgets(XtWindow(_form), w, h);
}
void PluginHostXt::setupWindow(int width, int height)
{
// Embed the Xt widget into the Qt widget
XReparentWindow(QX11Info::display(), XtWindow(_toplevel), _outside->winId(), 0, 0);
XtMapWidget(_toplevel);
setupPluginWindow(_plugin, (void*) XtWindow(_form), width, height);
}
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -39,9 +39,8 @@
class PluginHostXt : public PluginHost
{
public:
PluginHostXt(NSPluginInstance* plugin, QX11EmbedWidget* outside, int w, int h);
virtual void setupWindow(int width, int height);
virtual void resizePlugin(int width, int height);
PluginHostXt(NSPluginInstance* plugin);
virtual void setupWindow(int winId, int width, int height);
virtual ~PluginHostXt();
private:
static void forwarder(Widget w, XtPointer cl_data, XEvent * event, Boolean * cont);