update copyright date
[gnash.git] / plugin / klash4 / klash_part.cpp
blob144b118b5c9e49489ea019a1b7e2c9391b6f8244
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
4 //
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.
9 //
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.
14 //
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>
21 #ifdef KDE_USE_FINAL
22 #undef Always
23 #endif
25 #include "gnashconfig.h"
26 #include <cassert>
27 #include <QByteArray>
28 #include <QMenu>
29 #include <QTimer>
31 #include <klibloader.h>
32 #include <kdebug.h>
33 #include <kauthorized.h>
34 #include <kconfig.h>
35 #include <ksimpleconfig.h>
36 #include <kaction.h>
37 #include <kapplication.h>
38 #include <klocale.h>
39 #include <kcomponentdata.h>
40 #include <kactioncollection.h>
41 #include <kparts/factory.h>
43 #include "klash_part.h"
45 #include <csignal>
47 //-----------------------------------------------------------------------------
49 class KlashFactory : public KParts::Factory {
50 public:
51 KDE_NO_CDTOR_EXPORT KlashFactory ();
52 KDE_NO_CDTOR_EXPORT virtual ~KlashFactory ();
53 KDE_NO_CDTOR_EXPORT virtual KParts::Part *createPartObject
54 (QWidget *wparent,
55 QObject *parent,
56 const char *className, const QStringList &args);
57 static KComponentData * instance () { return s_instance; }
58 private:
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 () {
71 delete s_instance;
74 KParts::Part *KlashFactory::createPartObject
75 (QWidget *wparent,
76 QObject *parent,
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)),
96 m_process (0L),
97 m_width (0),
98 m_height (0),
99 m_autostart (false),
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("=");
122 if (equalPos > 0) {
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")) {
138 m_src_url = value;
139 } else if (name == QString::fromLatin1 ("fullscreenmode")) {
140 show_fullscreen = getBoolValue (value);
141 } else if (name == QString::fromLatin1 ("autostart")) {
142 bool ok;
143 m_autostart = value.toInt (&ok);
144 if (!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);
154 if (m_fullscreen)
155 fullScreen ();
158 KDE_NO_CDTOR_EXPORT KlashPart::~KlashPart () {
159 kdDebug() << "KlashPart::~KlashPart" << endl;
160 stop ();
161 //delete m_config;
162 //m_config = 0L;
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 ()
172 QString procname;
173 char *gnash_env = getenv("KLASH_PLAYER");
174 if (!gnash_env) {
175 procname = GNASHBINDIR "/kde4-gnash";
176 } else {
177 procname = gnash_env;
180 stop ();
181 if (m_src_url.isEmpty ())
182 return;
183 m_process = new KProcess;
184 m_process->setEnv (QString::fromLatin1 ("SESSION_MANAGER"), QString::fromLatin1 (""));
185 *m_process << procname
186 << "-x"
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();
194 if (!url.isEmpty())
195 *m_process << "-u" << url;
196 url = m_docbase.url();
197 if (!url.isEmpty())
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)));
207 m_process->start ();
210 KDE_NO_EXPORT void KlashPart::pause () {
213 KDE_NO_EXPORT void KlashPart::stop () {
214 if (m_process) {
215 if (m_process->state () == KProcess::Running) {
216 ; // IPC close
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();
223 assert(pid < -1);
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);
232 delete m_process;
233 m_process = 0L;
237 bool KlashPart::openFile() {
238 if (!localFilePath().isEmpty ())
239 m_src_url = localFilePath();
240 play ();
241 return true;
244 KDE_NO_EXPORT bool KlashPart::openUrl (const KUrl & url) {
245 kdDebug () << "KlashPart::openUrl " << url.url() << endl;
246 emit started (0);
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) {
271 emit completed ();
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);
282 emit completed ();
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) {
311 QString url;
312 stream >> url;
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 //---------------------------------------------------------------------
326 * add
327 * .error.errorCount
328 * .error.item(count)
329 * .errorDescription
330 * .errorCode
331 * .controls.stop()
332 * .controls.play()
335 enum JSCommand {
336 notsupported,
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 {
344 const char * name;
345 JSCommand command;
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];
373 return 0L;
375 int mid = (start + end) / 2;
376 int cmp = strcasecmp (JSCommandList[mid].name, name);
377 if (cmp < 0)
378 return getJSCommandEntry (name, mid + 1, end);
379 if (cmp > 0)
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),
387 m_started (false),
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 () {
397 m_started = true;
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);
405 m_started = true;
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);
417 if (!entry)
418 return false;
419 rid = id;
420 type = entry->rettype;
421 switch (entry->command) {
422 case prop_source:
423 type = KParts::LiveConnectExtension::TypeString;
424 rval = player->source ();
425 break;
426 case prop_volume:
427 //if (player->view ())
428 // rval = QString::number (??);
429 break;
430 default:
431 lastJSCommandEntry = entry;
432 type = KParts::LiveConnectExtension::TypeFunction;
434 return true;
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 ());
441 if (!entry)
442 return false;
443 switch (entry->command) {
444 case prop_source: {
445 KUrl url (val);
446 if (player->allowRedir (url))
447 player->openUrl (url);
448 break;
450 case prop_volume:
451 //if (player->view ())
452 // ?? (val.toInt ());
453 break;
454 default:
455 return false;
457 return true;
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);
468 if (!entry)
469 return false;
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 ());
475 //if (!view)
476 // return false;
477 rid = id;
478 type = entry->rettype;
479 switch (entry->command) {
480 case notsupported:
481 if (entry->rettype != KParts::LiveConnectExtension::TypeVoid)
482 rval = entry->defaultvalue;
483 break;
484 case play:
485 if (args.size ()) {
486 KUrl url (args.first ());
487 if (player->allowRedir (url)) {
488 ;//player->openNewUrl (url);
490 } else
491 player->play ();
492 rval = "true";
493 break;
494 case start:
495 player->play ();
496 rval = "true";
497 break;
498 case stop:
499 player->stop ();
500 rval = "true";
501 break;
502 case jsc_pause:
503 player->pause ();
504 rval = "true";
505 break;
506 case length:
507 rval.setNum (0 /*player->source ()->length ()*/);
508 break;
509 case width:
510 rval.setNum (player->width ());
511 break;
512 case height:
513 rval.setNum (player->height ());
514 break;
515 case setsource:
516 rval ="false";
517 if (args.size ()) {
518 KUrl url (args.first ());
519 if (player->allowRedir (url) && player->openUrl (url))
520 rval = "true";
522 break;
523 case setvolume:
524 if (!args.size ())
525 return false;
526 //?? (args.first ().toInt ());
527 rval = "true";
528 break;
529 case source:
530 rval = player->url ().url ();
531 break;
532 case volume:
533 if (player->widget ())
534 rval = QString::number (0);
535 break;
536 default:
537 return false;
539 return true;
542 KDE_NO_EXPORT void KlashLiveConnectExtension::unregister (const unsigned long) {
545 KDE_NO_EXPORT void KlashLiveConnectExtension::setSize (int w, int h) {
546 QByteArray jscode;
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);
552 args.clear();
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;
565 #undef KeyPress
566 #undef Always
567 #undef Never
568 #undef Status
569 #undef Unsorted
570 #undef Bool
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"