2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 // Written by Koos Vriezen <koos ! vriezen ? xs4all ! nl>
25 #include "gnashconfig.h"
31 #include <klibloader.h>
33 #include <kauthorized.h>
35 #include <ksimpleconfig.h>
37 #include <kapplication.h>
39 #include <kcomponentdata.h>
40 #include <kactioncollection.h>
41 #include <kparts/factory.h>
43 #include "klash_part.h"
47 //-----------------------------------------------------------------------------
49 class KlashFactory
: public KParts::Factory
{
51 KDE_NO_CDTOR_EXPORT
KlashFactory ();
52 KDE_NO_CDTOR_EXPORT
virtual ~KlashFactory ();
53 KDE_NO_CDTOR_EXPORT
virtual KParts::Part
*createPartObject
56 const char *className
, const QStringList
&args
);
57 static KComponentData
* instance () { return s_instance
; }
59 static KComponentData
* s_instance
;
62 K_EXPORT_COMPONENT_FACTORY (libklashpart
, KlashFactory
)
64 KComponentData
*KlashFactory::s_instance
= 0;
66 KlashFactory::KlashFactory () {
67 s_instance
= new KComponentData ("klash");
70 KlashFactory::~KlashFactory () {
74 KParts::Part
*KlashFactory::createPartObject
77 const char * /*cls*/, const QStringList
& args
) {
78 //kdDebug() << "KlashFactory::createPartObject " << cls << endl;
79 return new KlashPart (wparent
, parent
, args
);
82 //-----------------------------------------------------------------------------
84 static bool getBoolValue (const QString
& value
) {
85 return (value
.toLower() != QString::fromLatin1("false") &&
86 value
.toLower() != QString::fromLatin1("off") &&
87 value
.toLower() != QString::fromLatin1("0"));
90 KDE_NO_CDTOR_EXPORT
KlashPart::KlashPart (QWidget
* wparent
,
91 QObject
* parent
, const QStringList
&args
)
92 : KParts::ReadOnlyPart (parent
),
93 //new KSimpleConfig ("klashrc")),
94 m_browserextension (new KlashBrowserExtension (this)),
95 m_liveconnectextension (new KlashLiveConnectExtension (this)),
100 m_fullscreen (false),
101 m_started_emited (false) {
102 //kdDebug () << "KlashPart(" << this << ")::KlashPart ()" << endl;
103 bool show_fullscreen
= false;
104 // FIXME what is the right replacement for this? setInstance (KlashFactory::instance (), true);
105 KAction
*playact
= new KAction(this);
106 playact
->setText(i18n("P&lay"));
107 connect(playact
, SIGNAL(triggered()), this, SLOT(play()));
108 actionCollection()->addAction("play", playact
);
109 KAction
*pauseact
= new KAction(this);
110 pauseact
->setText(i18n("&Pause"));
111 connect(pauseact
, SIGNAL(triggered()), this, SLOT(pause()));
112 actionCollection()->addAction("pause", pauseact
);
113 KAction
*stopact
= new KAction(this);
114 stopact
->setText(i18n("&Stop"));
115 connect(stopact
, SIGNAL(triggered()), this, SLOT(stop()));
116 actionCollection()->addAction("stop", stopact
);
117 //new KAction (i18n ("Increase Volume"), QString ("player_volume"), KShortcut (), this, SLOT (increaseVolume ()), actionCollection (), "edit_volume_up");
118 //new KAction (i18n ("Decrease Volume"), QString ("player_volume"), KShortcut (), this, SLOT (decreaseVolume ()), actionCollection (), "edit_volume_down");
119 QStringList::const_iterator end
= args
.end ();
120 for (QStringList::const_iterator it
= args
.begin () ; it
!= end
; ++it
) {
121 int equalPos
= (*it
).indexOf("=");
123 QString name
= (*it
).left (equalPos
).toLower ();
124 QString value
= (*it
).right ((*it
).length () - equalPos
- 1);
125 if (value
.at(0)=='\"')
126 value
= value
.right (value
.length () - 1);
127 if (value
.at (value
.length () - 1) == '\"')
128 value
.truncate (value
.length () - 1);
129 //kdDebug () << "name=" << name << " value=" << value << endl;
130 if (name
== QString::fromLatin1("width")) {
131 m_width
= value
.toInt ();
132 } else if (name
== QString::fromLatin1("height")) {
133 m_height
= value
.toInt ();
134 //} else if (name == QString::fromLatin1("type")) {
135 } else if (name
== QString::fromLatin1("__khtml__pluginbaseurl")) {
136 m_docbase
= KUrl (value
);
137 } else if (name
== QString::fromLatin1("src")) {
139 } else if (name
== QString::fromLatin1 ("fullscreenmode")) {
140 show_fullscreen
= getBoolValue (value
);
141 } else if (name
== QString::fromLatin1 ("autostart")) {
143 m_autostart
= value
.toInt (&ok
);
145 m_autostart
= (value
.toLower () == "false");
147 m_args
.push_back(name
+ QChar('=') + value
);
150 KParts::Part::setWidget (new KlashView (wparent
));
151 setXMLFile("klashpartui.rc");
152 setProgressInfoEnabled (false);
158 KDE_NO_CDTOR_EXPORT
KlashPart::~KlashPart () {
159 kdDebug() << "KlashPart::~KlashPart" << endl
;
165 KDE_NO_EXPORT
bool KlashPart::allowRedir (const KUrl
& url
) const {
166 return KAuthorized::authorizeUrlAction ("redirect", m_docbase
, url
);
169 KDE_NO_EXPORT
void KlashPart::play ()
173 char *gnash_env
= getenv("KLASH_PLAYER");
175 procname
= GNASHBINDIR
"/kde4-gnash";
177 procname
= gnash_env
;
181 if (m_src_url
.isEmpty ())
183 m_process
= new KProcess
;
184 m_process
->setEnv (QString::fromLatin1 ("SESSION_MANAGER"), QString::fromLatin1 (""));
185 *m_process
<< procname
187 << QString::number(static_cast<KlashView
*>(widget())->embedId());
189 if (m_width
> 0 && m_height
> 0)
190 *m_process
<< "-j" << QString::number(m_width
)
191 << "-k" << QString::number(m_height
);
193 QString url
= this->url().url();
195 *m_process
<< "-u" << url
;
196 url
= m_docbase
.url();
198 *m_process
<< "-U" << url
;
200 for (QStringList::const_iterator it
=m_args
.begin(), end
=m_args
.end();it
!= end
; ++it
)
201 *m_process
<< "-P" << *it
;
203 *m_process
<< m_src_url
;
205 connect (m_process
, SIGNAL (finished (int, QProcess::ExitStatus
)),
206 this, SLOT (processStopped (int, QProcess::ExitStatus
)));
210 KDE_NO_EXPORT
void KlashPart::pause () {
213 KDE_NO_EXPORT
void KlashPart::stop () {
215 if (m_process
->state () == KProcess::Running
) {
217 //m_process->wait(2);
219 // Ignore SIGTERM, so we won't kill ourselves.
220 void (*oldhandler
)(int) = signal(SIGTERM
, SIG_IGN
);
222 int pid
= -1 * ::getpid();
225 // Terminate every process in our process group.
226 ::kill (pid
, SIGTERM
);
228 // Restore the old handler.
229 signal(SIGTERM
, oldhandler
);
230 m_process
->waitForFinished(2000);
237 bool KlashPart::openFile() {
238 if (!localFilePath().isEmpty ())
239 m_src_url
= localFilePath();
244 KDE_NO_EXPORT
bool KlashPart::openUrl (const KUrl
& url
) {
245 kdDebug () << "KlashPart::openUrl " << url
.url() << endl
;
247 return KParts::ReadOnlyPart::openUrl (url
);
250 KDE_NO_EXPORT
bool KlashPart::closeUrl () {
251 return KParts::ReadOnlyPart::closeUrl ();
254 KDE_NO_EXPORT
void KlashPart::fullScreen () {
257 KDE_NO_EXPORT
void KlashPart::setLoaded (int percentage
) {
258 if (percentage
< 100) {
259 m_browserextension
->setLoadingProgress (percentage
);
260 m_browserextension
->infoMessage
261 (QString::number (percentage
) + i18n ("% Cache fill"));
265 KDE_NO_EXPORT
void KlashPart::playingStarted () {
266 //kdDebug () << "KlashPart::processStartedPlaying " << endl;
267 //if (m_settings->sizeratio && !m_noresize && m_source->width() > 0 && m_source->height() > 0)
268 // m_liveconnectextension->setSize (m_source->width(), m_source->height());
269 m_browserextension
->setLoadingProgress (100);
270 if (m_started_emited
) {
272 m_started_emited
= false;
274 m_liveconnectextension
->started ();
275 m_browserextension
->infoMessage (i18n("Klash: Playing"));
278 KDE_NO_EXPORT
void KlashPart::playingStopped () {
279 if (m_started_emited
) {
280 m_started_emited
= false;
281 m_browserextension
->setLoadingProgress (100);
284 m_liveconnectextension
->finished ();
285 m_browserextension
->infoMessage (i18n ("Klash: Stop Playing"));
288 KDE_NO_EXPORT
void KlashPart::processStopped (int, QProcess::ExitStatus
) {
289 QTimer::singleShot (0, this, SLOT (playingStopped ()));
292 //---------------------------------------------------------------------
294 KDE_NO_CDTOR_EXPORT
KlashBrowserExtension::KlashBrowserExtension (KlashPart
* parent
)
295 : KParts::BrowserExtension (parent
) {
298 KDE_NO_EXPORT
void KlashBrowserExtension::urlChanged (const QString
& url
) {
299 emit
setLocationBarUrl (url
);
302 KDE_NO_EXPORT
void KlashBrowserExtension::setLoadingProgress (int percentage
) {
303 emit
loadingProgress (percentage
);
306 KDE_NO_EXPORT
void KlashBrowserExtension::saveState (QDataStream
& stream
) {
307 stream
<< static_cast <KlashPart
*> (parent ())->source ();
310 KDE_NO_EXPORT
void KlashBrowserExtension::restoreState (QDataStream
& stream
) {
313 static_cast <KlashPart
*> (parent ())->openUrl (KUrl(url
));
316 KDE_NO_EXPORT
void KlashBrowserExtension::requestOpenUrl (const KUrl
& url
, const QString
& /*target*/, const QString
& /*service*/) {
317 KParts::OpenUrlArguments args
;
318 //FIXME what replaces those?
319 //args.frameName = target;
320 //args.serviceType = service;
321 emit
openUrlRequest (url
, args
);
324 //---------------------------------------------------------------------
337 isfullscreen
, isloop
,
338 length
, width
, height
, position
, prop_source
, source
, setsource
,
339 play
, jsc_pause
, start
, stop
,
340 prop_volume
, volume
, setvolume
343 struct KLASH_NO_EXPORT JSCommandEntry
{
346 const char * defaultvalue
;
347 const KParts::LiveConnectExtension::Type rettype
;
350 // keep this list in alphabetic order
351 // http://service.real.com/help/library/guides/realonescripting/browse/htmfiles/embedmet.htm
352 static const JSCommandEntry JSCommandList
[] = {
353 { "GetSource", source
, 0L, KParts::LiveConnectExtension::TypeString
},
354 { "GetTitle", notsupported
, "title", KParts::LiveConnectExtension::TypeString
},
355 { "GetVolume", volume
, "100", KParts::LiveConnectExtension::TypeNumber
},
356 { "Pause", jsc_pause
, 0L, KParts::LiveConnectExtension::TypeBool
},
357 { "Play", play
, 0L, KParts::LiveConnectExtension::TypeBool
},
358 { "SetSource", setsource
, 0L, KParts::LiveConnectExtension::TypeBool
},
359 { "SetVolume", setvolume
, "true", KParts::LiveConnectExtension::TypeBool
},
360 { "Start", start
, 0L, KParts::LiveConnectExtension::TypeBool
},
361 { "Stop", stop
, 0L, KParts::LiveConnectExtension::TypeBool
},
362 { "Volume", prop_volume
, "100", KParts::LiveConnectExtension::TypeNumber
},
363 { "pause", jsc_pause
, 0L, KParts::LiveConnectExtension::TypeBool
},
364 { "play", play
, 0L, KParts::LiveConnectExtension::TypeBool
},
365 { "stop", stop
, 0L, KParts::LiveConnectExtension::TypeBool
},
366 { "volume", volume
, 0L, KParts::LiveConnectExtension::TypeBool
},
369 static const JSCommandEntry
* getJSCommandEntry (const char * name
, int start
= 0, int end
= sizeof (JSCommandList
)/sizeof (JSCommandEntry
)) {
370 if (end
- start
< 2) {
371 if (start
!= end
&& !strcasecmp (JSCommandList
[start
].name
, name
))
372 return &JSCommandList
[start
];
375 int mid
= (start
+ end
) / 2;
376 int cmp
= strcasecmp (JSCommandList
[mid
].name
, name
);
378 return getJSCommandEntry (name
, mid
+ 1, end
);
380 return getJSCommandEntry (name
, start
, mid
);
381 return &JSCommandList
[mid
];
384 KDE_NO_CDTOR_EXPORT
KlashLiveConnectExtension::KlashLiveConnectExtension (KlashPart
* parent
)
385 : KParts::LiveConnectExtension (parent
), player (parent
),
386 lastJSCommandEntry (0L),
388 m_enablefinish (false) {
389 connect (parent
, SIGNAL (started (KIO::Job
*)), this, SLOT (started ()));
392 KDE_NO_CDTOR_EXPORT
KlashLiveConnectExtension::~KlashLiveConnectExtension() {
393 //kdDebug () << "KlashLiveConnectExtension::~KlashLiveConnectExtension()" << endl;
396 KDE_NO_EXPORT
void KlashLiveConnectExtension::started () {
400 KDE_NO_EXPORT
void KlashLiveConnectExtension::finished () {
401 if (m_started
&& m_enablefinish
) {
402 KParts::LiveConnectExtension::ArgList args
;
403 args
.push_back (qMakePair (KParts::LiveConnectExtension::TypeString
, QString("if (window.onFinished) onFinished();")));
404 emit
partEvent (0, "eval", args
);
406 m_enablefinish
= false;
410 KDE_NO_EXPORT
bool KlashLiveConnectExtension::get
411 (const unsigned long id
, const QString
& name
,
412 KParts::LiveConnectExtension::Type
& type
,
413 unsigned long & rid
, QString
& rval
) {
414 const char * str
= name
.toAscii ();
415 kdDebug () << "\e[01;35mget\e[00m " << str
<< endl
;
416 const JSCommandEntry
* entry
= getJSCommandEntry (str
);
420 type
= entry
->rettype
;
421 switch (entry
->command
) {
423 type
= KParts::LiveConnectExtension::TypeString
;
424 rval
= player
->source ();
427 //if (player->view ())
428 // rval = QString::number (??);
431 lastJSCommandEntry
= entry
;
432 type
= KParts::LiveConnectExtension::TypeFunction
;
437 KDE_NO_EXPORT
bool KlashLiveConnectExtension::put
438 (const unsigned long, const QString
& name
, const QString
& val
) {
439 kdDebug () << "\e[01;35mput\e[00m " << name
<< "=" << val
<< endl
;
440 const JSCommandEntry
* entry
= getJSCommandEntry (name
.toAscii ());
443 switch (entry
->command
) {
446 if (player
->allowRedir (url
))
447 player
->openUrl (url
);
451 //if (player->view ())
452 // ?? (val.toInt ());
460 KDE_NO_EXPORT
bool KlashLiveConnectExtension::call
461 (const unsigned long id
, const QString
& name
,
462 const QStringList
& args
, KParts::LiveConnectExtension::Type
& type
,
463 unsigned long & rid
, QString
& rval
) {
464 const JSCommandEntry
* entry
= lastJSCommandEntry
;
465 const char * str
= name
.toAscii ();
466 if (!entry
|| strcmp (entry
->name
, str
))
467 entry
= getJSCommandEntry (str
);
470 kdDebug () << "\e[01;35mentry\e[00m " << entry
->name
<< endl
;
471 for (int i
= 0; i
< args
.size (); ++i
) {
472 kdDebug () << " " << args
[i
] << endl
;
474 //Klash::View * view = static_cast <Klash::View*> (player->widget ());
478 type
= entry
->rettype
;
479 switch (entry
->command
) {
481 if (entry
->rettype
!= KParts::LiveConnectExtension::TypeVoid
)
482 rval
= entry
->defaultvalue
;
486 KUrl
url (args
.first ());
487 if (player
->allowRedir (url
)) {
488 ;//player->openNewUrl (url);
507 rval
.setNum (0 /*player->source ()->length ()*/);
510 rval
.setNum (player
->width ());
513 rval
.setNum (player
->height ());
518 KUrl
url (args
.first ());
519 if (player
->allowRedir (url
) && player
->openUrl (url
))
526 //?? (args.first ().toInt ());
530 rval
= player
->url ().url ();
533 if (player
->widget ())
534 rval
= QString::number (0);
542 KDE_NO_EXPORT
void KlashLiveConnectExtension::unregister (const unsigned long) {
545 KDE_NO_EXPORT
void KlashLiveConnectExtension::setSize (int w
, int h
) {
547 //jscode.sprintf("this.width=%d;this.height=%d;klash", w, h);
548 KParts::LiveConnectExtension::ArgList args
;
549 args
.push_back (qMakePair (KParts::LiveConnectExtension::TypeString
, QString("width")));
550 args
.push_back (qMakePair (KParts::LiveConnectExtension::TypeNumber
, QString::number (w
)));
551 emit
partEvent (0, "this.setAttribute", args
);
553 args
.push_back (qMakePair (KParts::LiveConnectExtension::TypeString
, QString("height")));
554 args
.push_back (qMakePair (KParts::LiveConnectExtension::TypeNumber
, QString::number (h
)));
555 emit
partEvent (0, "this.setAttribute", args
);
558 //-----------------------------------------------------------------------------
560 #include <X11/Xlib.h>
561 #include <X11/keysym.h>
562 #include <X11/Intrinsic.h>
563 #include <X11/StringDefs.h>
564 static const int XKeyPress
= KeyPress
;
572 KlashEmbed::KlashEmbed (KlashView
* view
) : QX11EmbedWidget (view
), m_view (view
) {}
574 KlashEmbed::~KlashEmbed () {}
576 //-----------------------------------------------------------------------------
578 KlashView::KlashView (QWidget
* parent
)
579 : QWidget (parent
), m_embed (new KlashEmbed (this)) {}
581 KlashView::~KlashView () {}
583 void KlashView::resizeEvent (QResizeEvent
*) {
584 m_embed
->setGeometry (0, 0, width (), height ());
587 WId
KlashView::embedId () {
588 return m_embed
->winId ();
591 #include "klash_part.moc"