summaryrefslogtreecommitdiffstats
path: root/nsplugins/nspluginloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nsplugins/nspluginloader.cpp')
-rw-r--r--nsplugins/nspluginloader.cpp528
1 files changed, 528 insertions, 0 deletions
diff --git a/nsplugins/nspluginloader.cpp b/nsplugins/nspluginloader.cpp
new file mode 100644
index 000000000..91afa150d
--- /dev/null
+++ b/nsplugins/nspluginloader.cpp
@@ -0,0 +1,528 @@
+/*
+
+ This is an encapsulation of the Netscape plugin API.
+
+
+ Copyright (c) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
+ Stefan Schimanski <1Stein@gmx.de>
+ Copyright (c) 2002-2005 George Staikos <staikos@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#include <qdir.h>
+
+
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <dcopclient.h>
+#include <dcopstub.h>
+#include <qlayout.h>
+#include <qobject.h>
+#include <qpushbutton.h>
+#include <qxembed.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qregexp.h>
+
+#include "nspluginloader.h"
+#include "nspluginloader.moc"
+
+#include "NSPluginClassIface_stub.h"
+
+#include <config.h>
+
+NSPluginLoader *NSPluginLoader::s_instance = 0;
+int NSPluginLoader::s_refCount = 0;
+
+
+NSPluginInstance::NSPluginInstance(QWidget *parent)
+ : EMBEDCLASS(parent), _loader( NULL ), shown( false ), inited( false ), resize_count( 0 ), stub( NULL )
+{
+}
+
+void NSPluginInstance::init(const QCString& app, const QCString& obj)
+{
+ stub = new NSPluginInstanceIface_stub( app, obj );
+ QGridLayout *_layout = new QGridLayout(this, 1, 1);
+ KConfig cfg("kcmnspluginrc", false);
+ cfg.setGroup("Misc");
+ if (cfg.readBoolEntry("demandLoad", false)) {
+ _button = new QPushButton(i18n("Start Plugin"), dynamic_cast<EMBEDCLASS*>(this));
+ _layout->addWidget(_button, 0, 0);
+ connect(_button, SIGNAL(clicked()), this, SLOT(loadPlugin()));
+ show();
+ } else {
+ _button = 0L;
+ // Protection against repeated NPSetWindow() - Flash v9,0,115,0 doesn't handle
+ // repeated NPSetWindow() calls properly, which happens when NSPluginInstance is first
+ // shown and then resized. Which is what happens with KHTML. Therefore use 'shown'
+ // to detect whether the widget is shown and drop all resize events before that,
+ // and use 'resize_count' to wait for that one more resize to come (plus a timer
+ // for a possible timeout). Only then flash is actually initialized ('inited' is true).
+ resize_count = 1;
+ QTimer::singleShot( 1000, this, SLOT( doLoadPlugin()));
+ }
+}
+
+void NSPluginInstance::loadPlugin()
+{
+ delete _button;
+ _button = 0;
+ doLoadPlugin();
+}
+
+void NSPluginInstance::doLoadPlugin() {
+ if (!inited && !_button) {
+ _loader = NSPluginLoader::instance();
+ setBackgroundMode(QWidget::NoBackground);
+ WId winid = stub->winId();
+ if( winid != 0 ) {
+ setProtocol(QXEmbed::XPLAIN);
+ embed( winid );
+ } else {
+ setProtocol(QXEmbed::XEMBED);
+ }
+ // resize before showing, some plugins are stupid and can't handle repeated
+ // NPSetWindow() calls very well (viewer will avoid the call if not shown yet)
+ resizePlugin(width(), height());
+ displayPlugin();
+ show();
+ inited = true;
+ }
+}
+
+
+NSPluginInstance::~NSPluginInstance()
+{
+ kdDebug() << "-> NSPluginInstance::~NSPluginInstance" << endl;
+ if( inited )
+ shutdown();
+ kdDebug() << "release" << endl;
+ if(_loader)
+ _loader->release();
+ kdDebug() << "<- NSPluginInstance::~NSPluginInstance" << endl;
+ delete stub;
+}
+
+
+void NSPluginInstance::windowChanged(WId w)
+{
+ setBackgroundMode(w == 0 ? QWidget::PaletteBackground : QWidget::NoBackground);
+ if (w == 0) {
+ // FIXME: Put a notice here to tell the user that it crashed.
+ repaint();
+ }
+}
+
+
+void NSPluginInstance::resizeEvent(QResizeEvent *event)
+{
+ if (shown == false) // ignore all resizes before being shown
+ return;
+ if( !inited && resize_count > 0 ) {
+ if( --resize_count == 0 )
+ doLoadPlugin();
+ else
+ return;
+ }
+ EMBEDCLASS::resizeEvent(event);
+ if (isVisible()) {
+ resizePlugin(width(), height());
+ }
+ kdDebug() << "NSPluginInstance(client)::resizeEvent" << endl;
+}
+
+void NSPluginInstance::showEvent(QShowEvent *event)
+{
+ EMBEDCLASS::showEvent(event);
+ shown = true;
+ if(!inited && resize_count == 0 )
+ doLoadPlugin();
+ if(inited)
+ resizePlugin(width(), height());
+}
+
+void NSPluginInstance::focusInEvent( QFocusEvent* event )
+{
+ stub->gotFocusIn();
+}
+
+void NSPluginInstance::focusOutEvent( QFocusEvent* event )
+{
+ stub->gotFocusOut();
+}
+
+void NSPluginInstance::displayPlugin()
+{
+ qApp->syncX(); // process pending X commands
+ stub->displayPlugin();
+}
+
+void NSPluginInstance::resizePlugin( int w, int h )
+{
+ qApp->syncX();
+ stub->resizePlugin( w, h );
+}
+
+void NSPluginInstance::shutdown()
+{
+ if( stub )
+ stub->shutdown();
+}
+
+/*******************************************************************************/
+
+
+NSPluginLoader::NSPluginLoader()
+ : QObject(), _mapping(7, false), _viewer(0)
+{
+ scanPlugins();
+ _mapping.setAutoDelete( true );
+ _filetype.setAutoDelete(true);
+
+ // trap dcop register events
+ kapp->dcopClient()->setNotifications(true);
+ QObject::connect(kapp->dcopClient(),
+ SIGNAL(applicationRegistered(const QCString&)),
+ this, SLOT(applicationRegistered(const QCString&)));
+
+ // load configuration
+ KConfig cfg("kcmnspluginrc", false);
+ cfg.setGroup("Misc");
+ _useArtsdsp = cfg.readBoolEntry( "useArtsdsp", false );
+}
+
+
+NSPluginLoader *NSPluginLoader::instance()
+{
+ if (!s_instance)
+ s_instance = new NSPluginLoader;
+
+ s_refCount++;
+ kdDebug() << "NSPluginLoader::instance -> " << s_refCount << endl;
+
+ return s_instance;
+}
+
+
+void NSPluginLoader::release()
+{
+ s_refCount--;
+ kdDebug() << "NSPluginLoader::release -> " << s_refCount << endl;
+
+ if (s_refCount==0)
+ {
+ delete s_instance;
+ s_instance = 0;
+ }
+}
+
+
+NSPluginLoader::~NSPluginLoader()
+{
+ kdDebug() << "-> NSPluginLoader::~NSPluginLoader" << endl;
+ unloadViewer();
+ kdDebug() << "<- NSPluginLoader::~NSPluginLoader" << endl;
+}
+
+
+void NSPluginLoader::scanPlugins()
+{
+ QRegExp version(";version=[^:]*:");
+
+ // open the cache file
+ QFile cachef(locate("data", "nsplugins/cache"));
+ if (!cachef.open(IO_ReadOnly)) {
+ kdDebug() << "Could not load plugin cache file!" << endl;
+ return;
+ }
+
+ QTextStream cache(&cachef);
+
+ // read in cache
+ QString line, plugin;
+ while (!cache.atEnd()) {
+ line = cache.readLine();
+ if (line.isEmpty() || (line.left(1) == "#"))
+ continue;
+
+ if (line.left(1) == "[")
+ {
+ plugin = line.mid(1,line.length()-2);
+ continue;
+ }
+
+ QStringList desc = QStringList::split(':', line, TRUE);
+ QString mime = desc[0].stripWhiteSpace();
+ QStringList suffixes = QStringList::split(',', desc[1].stripWhiteSpace());
+ if (!mime.isEmpty())
+ {
+ // insert the mimetype -> plugin mapping
+ _mapping.insert(mime, new QString(plugin));
+
+ // insert the suffix -> mimetype mapping
+ QStringList::Iterator suffix;
+ for (suffix = suffixes.begin(); suffix != suffixes.end(); ++suffix) {
+
+ // strip whitspaces and any preceding '.'
+ QString stripped = (*suffix).stripWhiteSpace();
+
+ unsigned p=0;
+ for ( ; p<stripped.length() && stripped[p]=='.'; p++ );
+ stripped = stripped.right( stripped.length()-p );
+
+ // add filetype to list
+ if ( !stripped.isEmpty() && !_filetype.find(stripped) )
+ _filetype.insert( stripped, new QString(mime));
+ }
+ }
+ }
+}
+
+
+QString NSPluginLoader::lookupMimeType(const QString &url)
+{
+ QDictIterator<QString> dit2(_filetype);
+ while (dit2.current())
+ {
+ QString ext = QString(".")+dit2.currentKey();
+ if (url.right(ext.length()) == ext)
+ return *dit2.current();
+ ++dit2;
+ }
+ return QString::null;
+}
+
+
+QString NSPluginLoader::lookup(const QString &mimeType)
+{
+ QString plugin;
+ if ( _mapping[mimeType] )
+ plugin = *_mapping[mimeType];
+
+ kdDebug() << "Looking up plugin for mimetype " << mimeType << ": " << plugin << endl;
+
+ return plugin;
+}
+
+
+bool NSPluginLoader::loadViewer()
+{
+ kdDebug() << "NSPluginLoader::loadViewer" << endl;
+
+ _running = false;
+ _process = new KProcess;
+
+ // get the dcop app id
+ int pid = (int)getpid();
+ _dcopid.sprintf("nspluginviewer-%d", pid);
+
+ connect( _process, SIGNAL(processExited(KProcess*)),
+ this, SLOT(processTerminated(KProcess*)) );
+
+ // find the external viewer process
+ QString viewer = KGlobal::dirs()->findExe("nspluginviewer");
+ if (!viewer)
+ {
+ kdDebug() << "can't find nspluginviewer" << endl;
+ delete _process;
+ return false;
+ }
+
+ // find the external artsdsp process
+ if( _useArtsdsp ) {
+ kdDebug() << "trying to use artsdsp" << endl;
+ QString artsdsp = KGlobal::dirs()->findExe("artsdsp");
+ if (!artsdsp)
+ {
+ kdDebug() << "can't find artsdsp" << endl;
+ } else
+ {
+ kdDebug() << artsdsp << endl;
+ *_process << artsdsp;
+ }
+ } else
+ kdDebug() << "don't using artsdsp" << endl;
+
+ *_process << viewer;
+
+ // tell the process it's parameters
+ *_process << "-dcopid";
+ *_process << _dcopid;
+
+ // run the process
+ kdDebug() << "Running nspluginviewer" << endl;
+ _process->start();
+
+ // wait for the process to run
+ int cnt = 0;
+ while (!kapp->dcopClient()->isApplicationRegistered(_dcopid))
+ {
+ //kapp->processEvents(); // would lead to recursive calls in khtml
+#ifdef HAVE_USLEEP
+ usleep( 50*1000 );
+#else
+ sleep(1); kdDebug() << "sleep" << endl;
+#endif
+ cnt++;
+#ifdef HAVE_USLEEP
+ if (cnt >= 100)
+#else
+ if (cnt >= 10)
+#endif
+ {
+ kdDebug() << "timeout" << endl;
+ delete _process;
+ return false;
+ }
+
+ if (!_process->isRunning())
+ {
+ kdDebug() << "nspluginviewer terminated" << endl;
+ delete _process;
+ return false;
+ }
+ }
+
+ // get viewer dcop interface
+ _viewer = new NSPluginViewerIface_stub( _dcopid, "viewer" );
+
+ return _viewer!=0;
+}
+
+
+void NSPluginLoader::unloadViewer()
+{
+ kdDebug() << "-> NSPluginLoader::unloadViewer" << endl;
+
+ if ( _viewer )
+ {
+ _viewer->shutdown();
+ kdDebug() << "Shutdown viewer" << endl;
+ delete _viewer;
+ delete _process;
+ _viewer = 0;
+ _process = 0;
+ }
+
+ kdDebug() << "<- NSPluginLoader::unloadViewer" << endl;
+}
+
+
+void NSPluginLoader::applicationRegistered( const QCString& appId )
+{
+ kdDebug() << "DCOP application " << appId.data() << " just registered!" << endl;
+
+ if ( _dcopid==appId )
+ {
+ _running = true;
+ kdDebug() << "plugin now running" << endl;
+ }
+}
+
+
+void NSPluginLoader::processTerminated(KProcess *proc)
+{
+ if ( _process == proc)
+ {
+ kdDebug() << "Viewer process terminated" << endl;
+ delete _viewer;
+ delete _process;
+ _viewer = 0;
+ _process = 0;
+ }
+}
+
+
+NSPluginInstance *NSPluginLoader::newInstance(QWidget *parent, QString url,
+ QString mimeType, bool embed,
+ QStringList argn, QStringList argv,
+ QString appId, QString callbackId, bool reload, bool doPost, QByteArray postData)
+{
+ kdDebug() << "-> NSPluginLoader::NewInstance( parent=" << (void*)parent << ", url=" << url << ", mime=" << mimeType << ", ...)" << endl;
+
+ if ( !_viewer )
+ {
+ // load plugin viewer process
+ loadViewer();
+
+ if ( !_viewer )
+ {
+ kdDebug() << "No viewer dcop stub found" << endl;
+ return 0;
+ }
+ }
+
+ // check the mime type
+ QString mime = mimeType;
+ if (mime.isEmpty())
+ {
+ mime = lookupMimeType( url );
+ argn << "MIME";
+ argv << mime;
+ }
+ if (mime.isEmpty())
+ {
+ kdDebug() << "Unknown MimeType" << endl;
+ return 0;
+ }
+
+ // lookup plugin for mime type
+ QString plugin_name = lookup(mime);
+ if (plugin_name.isEmpty())
+ {
+ kdDebug() << "No suitable plugin" << endl;
+ return 0;
+ }
+
+ // get plugin class object
+ DCOPRef cls_ref = _viewer->newClass( plugin_name );
+ if ( cls_ref.isNull() )
+ {
+ kdDebug() << "Couldn't create plugin class" << endl;
+ return 0;
+ }
+ NSPluginClassIface_stub *cls = new NSPluginClassIface_stub( cls_ref.app(), cls_ref.object() );
+
+ // handle special plugin cases
+ if ( mime=="application/x-shockwave-flash" )
+ embed = true; // flash doesn't work in full mode :(
+
+ NSPluginInstance *plugin = new NSPluginInstance( parent );
+ kdDebug() << "<- NSPluginLoader::NewInstance = " << (void*)plugin << endl;
+
+ // get plugin instance
+ DCOPRef inst_ref = cls->newInstance( url, mime, embed, argn, argv, appId, callbackId, reload, doPost, postData, plugin->winId());
+ if ( inst_ref.isNull() )
+ {
+ kdDebug() << "Couldn't create plugin instance" << endl;
+ delete plugin;
+ return 0;
+ }
+
+ plugin->init( inst_ref.app(), inst_ref.object() );
+
+ return plugin;
+}
+
+// vim: ts=4 sw=4 et