3 This is an encapsulation of the Netscape plugin API.
6 Copyright (c) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
7 Stefan Schimanski <1Stein@gmx.de>
8 Copyright (c) 2002-2005 George Staikos <staikos@kde.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "nspluginloader.h"
27 #include "nspluginloader.moc"
30 #include <QGridLayout>
31 #include <QResizeEvent>
34 #include <kapplication.h>
39 #include <kstandarddirs.h>
41 #include <kconfiggroup.h>
44 #include <QPushButton>
45 #include <QtGui/QX11EmbedContainer>
46 #include <QTextStream>
50 #include "nsplugins_class_interface.h"
51 #include "nsplugins_instance_interface.h"
52 #include "nsplugins_viewer_interface.h"
54 #include <config-apps.h>
59 NSPluginLoader
*NSPluginLoader::s_instance
= 0;
60 int NSPluginLoader::s_refCount
= 0;
63 NSPluginInstance::NSPluginInstance(QWidget
*parent
, const QString
& viewerDBusId
, const QString
& id
, const KUrl
& baseUrl
)
64 : EMBEDCLASS(parent
), _loader(0), inited(false), haveSize(false), _button(0)
66 setWindowTitle("nsp.host"); // for debugging..
67 _instanceInterface
= new org::kde::nsplugins::Instance( viewerDBusId
, id
, QDBusConnection::sessionBus() );
69 QGridLayout
*_layout
= new QGridLayout(this);
70 _layout
->setMargin(1);
71 _layout
->setSpacing(1);
72 KConfig
_cfg( "kcmnspluginrc" );
73 KConfigGroup
cfg(&_cfg
, "Misc");
74 if (cfg
.readEntry("demandLoad", false)) {
75 KSharedConfigPtr config
= KSharedConfig::openConfig("konquerorrc");
76 KConfigGroup
settings(config
, "Java/JavaScript Settings");
77 if (settings
.readEntry("PluginDomains", QStringList()).contains(baseUrl
.host())) {
78 KConfigGroup
pluginDomains(config
, baseUrl
.host());
79 if (pluginDomains
.readEntry("plugins.EnablePlugins", false)) {
83 _button
= new QPushButton(i18n("Start Plugin"), this);
84 _layout
->addWidget(_button
, 0, 0);
85 connect(_button
, SIGNAL(clicked()), this, SLOT(loadPlugin()));
90 void NSPluginInstance::loadPlugin()
94 doLoadPlugin(width(), height());
97 void NSPluginInstance::doLoadPlugin(int w
, int h
) {
98 if (!inited
&& !_button
) {
99 _loader
= NSPluginLoader::instance();
100 // resize before showing, some plugins are stupid and can't handle repeated
101 // NPSetWindow() calls very well (viewer will avoid the call if not shown yet)
103 _instanceInterface
->setupWindow(winId(), w
, h
);
108 NSPluginInstance::~NSPluginInstance()
110 kDebug() << "-> NSPluginInstance::~NSPluginInstance";
111 _instanceInterface
->shutdown();
112 kDebug() << "release";
115 kDebug() << "<- NSPluginInstance::~NSPluginInstance";
119 void NSPluginInstance::windowChanged(WId w
)
122 // FIXME: Put a notice here to tell the user that it crashed.
127 void NSPluginInstance::pluginResized(int w
, int h
)
134 void NSPluginInstance::embedIfNeeded(int w
, int h
)
137 if (haveSize
&& !inited
)
144 void NSPluginInstance::resizeEvent(QResizeEvent
*event
)
146 kDebug() << width() << height() << isVisible() << haveSize
<< inited
;
147 EMBEDCLASS::resizeEvent(event
);
149 embedIfNeeded(width(), height());
152 void NSPluginInstance::showEvent(QShowEvent
*event
)
154 kDebug() << width() << height() << isVisible() << haveSize
<< inited
;
155 EMBEDCLASS::showEvent(event
);
157 embedIfNeeded(width(), height());
160 void NSPluginInstance::javascriptResult(int id
, const QString
&result
)
162 _instanceInterface
->javascriptResult( id
, result
);
165 void NSPluginInstance::focusInEvent( QFocusEvent
* event
)
168 _instanceInterface
->gotFocusIn();
171 void NSPluginInstance::focusOutEvent( QFocusEvent
* event
)
174 _instanceInterface
->gotFocusOut();
177 void NSPluginInstance::resizePlugin( int w
, int h
)
180 _instanceInterface
->resizePlugin( clientWinId(), w
, h
);
183 /*******************************************************************************/
186 NSPluginLoader::NSPluginLoader()
187 : QObject(), _mapping(), _viewer(0)
193 NSPluginLoader
*NSPluginLoader::instance()
196 s_instance
= new NSPluginLoader
;
199 kDebug() << "NSPluginLoader::instance -> " << s_refCount
;
205 void NSPluginLoader::release()
208 kDebug() << "NSPluginLoader::release -> " << s_refCount
;
218 NSPluginLoader::~NSPluginLoader()
220 kDebug() << "-> NSPluginLoader::~NSPluginLoader";
222 kDebug() << "<- NSPluginLoader::~NSPluginLoader";
226 void NSPluginLoader::scanPlugins()
228 QRegExp
version(";version=[^:]*:");
230 // open the cache file
231 QFile
cachef(KStandardDirs::locate("data", "nsplugins/cache"));
232 if (!cachef
.open(QIODevice::ReadOnly
)) {
233 kDebug() << "Could not load plugin cache file!";
237 QTextStream
cache(&cachef
);
240 QString line
, plugin
;
241 while (!cache
.atEnd()) {
242 line
= cache
.readLine();
243 if (line
.isEmpty() || (line
.left(1) == "#"))
246 if (line
.left(1) == "[")
248 plugin
= line
.mid(1,line
.length()-2);
252 QStringList desc
= line
.split(':', QString::KeepEmptyParts
);
253 // avoid crash on broken lines
257 QString mime
= desc
[0].trimmed();
258 QStringList suffixes
;
259 // If there are no suffixes, this would cause a crash
260 if (desc
.count() > 1)
261 suffixes
= desc
[1].trimmed().split(',');
264 // insert the mimetype -> plugin mapping
265 _mapping
.insert(mime
, QString(plugin
).toLower());
267 // insert the suffix -> mimetype mapping
268 QStringList::Iterator suffix
;
269 for (suffix
= suffixes
.begin(); suffix
!= suffixes
.end(); ++suffix
) {
271 // strip whitspaces and any preceding '.'
272 QString stripped
= (*suffix
).trimmed();
275 for ( ; p
<stripped
.length() && stripped
[p
]=='.'; p
++ ) {
278 stripped
= stripped
.right( stripped
.length()-p
);
280 // add filetype to list
281 if ( !stripped
.isEmpty() && !_filetype
.contains(stripped
) )
282 _filetype
.insert( stripped
, QString(mime
));
289 QString
NSPluginLoader::lookupMimeType(const QString
&url
)
292 QHashIterator
<QString
, QString
> dit2(_filetype
);
293 while ( dit2
.hasNext() ) {
295 QString ext
= QString(".")+dit2
.key();
296 if (url
.right(ext
.length()) == ext
) {
297 result
= dit2
.value();
306 QString
NSPluginLoader::lookup(const QString
&mimeType
)
309 if ( _mapping
.contains(mimeType
) )
310 plugin
= _mapping
.value(mimeType
);
312 kDebug() << "Looking up plugin for mimetype " << mimeType
<< ": " << plugin
;
318 bool NSPluginLoader::loadViewer()
320 kDebug() << "NSPluginLoader::loadViewer";
322 _process
.clearProgram();
323 // get the dbus app id
324 int pid
= (int)getpid();
326 tmp
.sprintf("org.kde.nspluginviewer-%d",pid
);
327 _viewerDBusId
=tmp
.toLatin1();
329 connect( &_process
, SIGNAL(finished(int, QProcess::ExitStatus
)),
330 this, SLOT(processTerminated()) );
332 // find the external viewer process
333 QString viewer
= KGlobal::dirs()->findExe("nspluginviewer");
334 if (viewer
.isEmpty())
336 kDebug() << "can't find nspluginviewer";
342 _process
<< "-dbusservice";
343 _process
<< _viewerDBusId
;
346 kDebug() << "Running nspluginviewer";
349 // wait for the process to run
351 while (!QDBusConnection::sessionBus().interface()->isServiceRegistered(_viewerDBusId
))
353 //kapp->processEvents(); // would lead to recursive calls in khtml
357 sleep(1); kDebug() << "sleep";
366 kDebug() << "timeout";
371 if (_process
.state() == QProcess::NotRunning
)
373 kDebug() << "nspluginviewer terminated";
378 // get viewer dcop interface
379 _viewer
= new org::kde::nsplugins::Viewer( _viewerDBusId
, "/Viewer", QDBusConnection::sessionBus() );
385 void NSPluginLoader::unloadViewer()
387 kDebug() << "-> NSPluginLoader::unloadViewer";
392 kDebug() << "Shutdown viewer";
398 kDebug() << "<- NSPluginLoader::unloadViewer";
404 void NSPluginLoader::processTerminated()
406 kDebug() << "Viewer process terminated";
412 NSPluginInstance
*NSPluginLoader::newInstance(QWidget
*parent
, const QString
& url
,
413 const QString
& mimeType
, bool embed
,
414 const QStringList
& _argn
, const QStringList
& _argv
,
415 const QString
& ownDBusId
, const QString
& callbackId
, bool reload
)
417 kDebug() << "-> NSPluginLoader::NewInstance( parent=" << (void*)parent
<< ", url=" << url
<< ", mime=" << mimeType
<< ", " << _argn
<< _argv
<< ")";
421 // load plugin viewer process
426 kDebug() << "No viewer dbus stub found";
431 kDebug() << "-> ownID" << ownDBusId
<< " viewer ID:" << _viewerDBusId
;
433 QStringList
argn( _argn
);
434 QStringList
argv( _argv
);
436 // check the mime type
437 QString mime
= mimeType
;
440 mime
= lookupMimeType( url
);
446 kDebug() << "Unknown MimeType";
450 // lookup plugin for mime type
451 QString plugin_name
= lookup(mime
);
452 if (plugin_name
.isEmpty())
454 kDebug() << "No suitable plugin";
458 // get plugin class object
459 QDBusObjectPath cls_ref
= _viewer
->newClass( plugin_name
, ownDBusId
);
460 if ( cls_ref
.path().isEmpty() )
462 kDebug() << "Couldn't create plugin class";
466 org::kde::nsplugins::Class
* cls
= new org::kde::nsplugins::Class( _viewerDBusId
, cls_ref
.path(), QDBusConnection::sessionBus() );
468 // handle special plugin cases
469 if ( mime
=="application/x-shockwave-flash" )
470 embed
= true; // flash doesn't work in full mode :(
473 // get plugin instance
474 QDBusObjectPath inst_ref
= cls
->newInstance( url
, mime
, embed
, argn
, argv
, ownDBusId
, callbackId
, reload
);
475 if ( inst_ref
.path().isEmpty() )
477 kDebug() << "Couldn't create plugin instance";
483 const int indexOfBaseurl
= argn
.indexOf( "__KHTML__PLUGINBASEURL" );
484 if ( indexOfBaseurl
> 0 ) {
485 baseUrl
= argv
.at( indexOfBaseurl
);
488 NSPluginInstance
*plugin
= new NSPluginInstance( parent
, _viewerDBusId
, inst_ref
.path(), baseUrl
);
490 kDebug() << "<- NSPluginLoader::NewInstance = " << (void*)plugin
;
497 // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;