File indexing completed on 2024-04-14 15:01:11

0001 /* This file is part of the KMPlayer application
0002    Copyright (C) 2004 Koos Vriezen <koos.vriezen@xs4all.nl>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012     General Public License for more details.
0013 
0014    You should have received a copy of the GNU General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include <math.h>
0021 #include <unistd.h>
0022 
0023 #include <qlayout.h>
0024 #include <qlabel.h>
0025 #include <qmap.h>
0026 #include <qtimer.h>
0027 #include <qpushbutton.h>
0028 #include <Q3ButtonGroup>
0029 #include <qcheckbox.h>
0030 #include <qtable.h>
0031 #include <qstringlist.h>
0032 #include <qcombobox.h>
0033 #include <qlineedit.h>
0034 #include <qgroupbox.h>
0035 #include <qwhatsthis.h>
0036 #include <qtabwidget.h>
0037 #include <qradiobutton.h>
0038 #include <qmessagebox.h>
0039 #include <qpopupmenu.h>
0040 #include <qsocket.h>
0041 #include <qeventloop.h>
0042 
0043 #include <klocalizedstring.h>
0044 #include <kdebug.h>
0045 #include <kmessagebox.h>
0046 #include <klineedit.h>
0047 #include <kurlrequester.h>
0048 #include <kcombobox.h>
0049 #include <kstatusbar.h>
0050 #include <kprocess.h>
0051 #include <kconfig.h>
0052 #include <kaction.h>
0053 #include <kiconloader.h>
0054 #include <klistview.h>
0055 #include <kdeversion.h>
0056 #include <kinputdialog.h>
0057 
0058 #include "kmplayer_backend_stub.h"
0059 #include "kmplayer_callback.h"
0060 #include "kmplayerpartbase.h"
0061 #include "kmplayercontrolpanel.h"
0062 #include "kmplayerconfig.h"
0063 #include "playlistview.h"
0064 #include "viewarea.h"
0065 #include "kmplayervdr.h"
0066 #include "kmplayer.h"
0067 
0068 using namespace KMPlayer;
0069 
0070 static const char * strVDR = "VDR";
0071 static const char * strVDRPort = "Port";
0072 static const char * strXVPort = "XV Port";
0073 static const char * strXVEncoding = "XV Encoding";
0074 static const char * strXVScale = "XV Scale";
0075 
0076 KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageVDR::KMPlayerPrefSourcePageVDR (QWidget * parent, KMPlayer::PartBase * player)
0077  : QFrame (parent), m_player (player) {
0078     //KUrlRequester * v4ldevice;
0079     QVBoxLayout *layout = new QVBoxLayout (this, 5, 2);
0080     QGridLayout *gridlayout = new QGridLayout (1, 2);
0081     xv_port = new KListView (this);
0082     xv_port->addColumn (QString());
0083     xv_port->header()->hide ();
0084     xv_port->setTreeStepSize (15);
0085     //xv_port->setRootIsDecorated (true);
0086     //xv_port->setSorting (-1);
0087     Q3ListViewItem * vitem = new Q3ListViewItem (xv_port, i18n ("XVideo port"));
0088     vitem->setOpen (true);
0089     QWhatsThis::add (xv_port, i18n ("Port base of the X Video extension.\nIf left to default (0), the first available port will be used. However if you have multiple XVideo instances, you might have to provide the port to use here.\nSee the output from 'xvinfo' for more information"));
0090     QLabel * label = new QLabel (i18n ("Communication port:"), this);
0091     gridlayout->addWidget (label, 0, 0);
0092     tcp_port = new QLineEdit ("", this);
0093     QWhatsThis::add (tcp_port, i18n ("Communication port with VDR. Default is port 2001.\nIf you use another port, with the '-p' option of 'vdr', you must set it here too."));
0094     gridlayout->addWidget (tcp_port, 0, 1);
0095     layout->addWidget (xv_port);
0096     layout->addLayout (gridlayout);
0097     scale = new Q3ButtonGroup (2, Qt::Vertical, i18n ("Scale"), this);
0098     new QRadioButton (i18n ("4:3"), scale);
0099     new QRadioButton (i18n ("16:9"), scale);
0100     QWhatsThis::add (scale, i18n ("Aspects to use when viewing VDR"));
0101     scale->setButton (0);
0102     layout->addWidget (scale);
0103     layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
0104 }
0105 
0106 KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageVDR::~KMPlayerPrefSourcePageVDR () {}
0107 
0108 KDE_NO_EXPORT void KMPlayerPrefSourcePageVDR::showEvent (QShowEvent *) {
0109     XvProcessInfo *pi = static_cast<XvProcessInfo *>(m_player->mediaManager()->
0110             processInfos()["xvideo"]);
0111     if (!pi->config_doc)
0112         pi->getConfigData ();
0113 }
0114 //-----------------------------------------------------------------------------
0115 
0116 static const char * cmd_chan_query = "CHAN\n";
0117 static const char * cmd_list_channels = "LSTC\n";
0118 static const char * cmd_volume_query = "VOLU\n";
0119 
0120 class VDRCommand {
0121 public:
0122     KDE_NO_CDTOR_EXPORT VDRCommand (const char * c, VDRCommand * n=0L)
0123         : command (strdup (c)), next (n) {}
0124     KDE_NO_CDTOR_EXPORT ~VDRCommand () { free (command); }
0125     char * command;
0126     VDRCommand * next;
0127 };
0128 
0129 //-----------------------------------------------------------------------------
0130 
0131 KDE_NO_CDTOR_EXPORT KMPlayerVDRSource::KMPlayerVDRSource (KMPlayerApp * app)
0132  : KMPlayer::Source (QString ("VDR"), app->player (), "vdrsource"),
0133    m_app (app),
0134    m_configpage (0),
0135    m_socket (new QSocket (this)), 
0136    commands (0L),
0137    channel_timer (0),
0138    timeout_timer (0),
0139    finish_timer (0),
0140    tcp_port (0),
0141    m_stored_volume (0) {
0142     memset (m_actions, 0, sizeof (KAction *) * int (act_last));
0143     m_player->settings ()->addPage (this);
0144     connect (m_socket, SIGNAL (connectionClosed()), this, SLOT(disconnected()));
0145     connect (m_socket, SIGNAL (connected ()), this, SLOT (connected ()));
0146     connect (m_socket, SIGNAL (readyRead ()), this, SLOT (readyRead ()));
0147     connect (m_socket, SIGNAL (error (int)), this, SLOT (socketError (int)));
0148 }
0149 
0150 KDE_NO_CDTOR_EXPORT KMPlayerVDRSource::~KMPlayerVDRSource () {}
0151 
0152 KDE_NO_CDTOR_EXPORT void KMPlayerVDRSource::waitForConnectionClose () {
0153     if (timeout_timer) {
0154         finish_timer = startTimer (500);
0155         kdDebug () << "VDR connection not yet closed" << endl;
0156         QApplication::eventLoop ()->enterLoop ();
0157         kdDebug () << "VDR connection:" << (m_socket->state () == QSocket::Connected) << endl;
0158         timeout_timer = 0;
0159     }
0160 }
0161 
0162 KDE_NO_EXPORT bool KMPlayerVDRSource::hasLength () {
0163     return false;
0164 }
0165 
0166 KDE_NO_EXPORT bool KMPlayerVDRSource::isSeekable () {
0167     return true;
0168 }
0169 
0170 KDE_NO_EXPORT QString KMPlayerVDRSource::prettyName () {
0171     return i18n ("VDR");
0172 }
0173 
0174 KDE_NO_EXPORT void KMPlayerVDRSource::activate () {
0175     last_channel = 0;
0176     connect (this, SIGNAL (startPlaying ()), this, SLOT (processStarted()));
0177     connect (this, SIGNAL (stopPlaying ()), this, SLOT (processStopped ()));
0178     KMPlayer::ControlPanel * panel = m_app->view()->controlPanel ();
0179     panel->button (KMPlayer::ControlPanel::button_red)->show ();
0180     panel->button (KMPlayer::ControlPanel::button_green)->show ();
0181     panel->button (KMPlayer::ControlPanel::button_yellow)->show ();
0182     panel->button (KMPlayer::ControlPanel::button_blue)->show ();
0183     panel->button (KMPlayer::ControlPanel::button_pause)->hide ();
0184     panel->button (KMPlayer::ControlPanel::button_record)->hide ();
0185     connect (panel->volumeBar (), SIGNAL (volumeChanged (int)), this, SLOT (volumeChanged (int)));
0186     connect (panel->button (KMPlayer::ControlPanel::button_red), SIGNAL (clicked ()), this, SLOT (keyRed ()));
0187     connect (panel->button (KMPlayer::ControlPanel::button_green), SIGNAL (clicked ()), this, SLOT (keyGreen ()));
0188     connect (panel->button (KMPlayer::ControlPanel::button_yellow), SIGNAL (clicked ()), this, SLOT (keyYellow ()));
0189     connect (panel->button (KMPlayer::ControlPanel::button_blue), SIGNAL (clicked ()), this, SLOT (keyBlue ()));
0190     setAspect (m_document, scale ? 16.0/9 : 1.33);
0191     if (!m_url.protocol ().compare ("kmplayer"))
0192         m_request_jump = KUrl::decode_string (m_url.path ()).mid (1);
0193     setUrl (QString ("vdr://localhost:%1").arg (tcp_port));
0194     QTimer::singleShot (0, m_player, SLOT (play ()));
0195 }
0196 
0197 KDE_NO_EXPORT void KMPlayerVDRSource::deactivate () {
0198     disconnect (m_socket, SIGNAL (error (int)), this, SLOT (socketError (int)));
0199     if (m_player->view ()) {
0200         disconnect (this, SIGNAL(startPlaying()), this, SLOT(processStarted()));
0201         disconnect (this, SIGNAL (stopPlaying()), this, SLOT(processStopped()));
0202         KMPlayer::ControlPanel * panel = m_app->view()->controlPanel ();
0203         disconnect (panel->volumeBar (), SIGNAL (volumeChanged (int)), this, SLOT (volumeChanged (int)));
0204         disconnect (panel->button (KMPlayer::ControlPanel::button_red), SIGNAL (clicked ()), this, SLOT (keyRed ()));
0205         disconnect (panel->button (KMPlayer::ControlPanel::button_green), SIGNAL (clicked ()), this, SLOT (keyGreen ()));
0206         disconnect (panel->button (KMPlayer::ControlPanel::button_yellow), SIGNAL (clicked ()), this, SLOT (keyYellow ()));
0207         disconnect (panel->button (KMPlayer::ControlPanel::button_blue), SIGNAL (clicked ()), this, SLOT (keyBlue ()));
0208     }
0209     processStopped ();
0210     m_request_jump.truncate (0);
0211 }
0212 
0213 KDE_NO_EXPORT void KMPlayerVDRSource::processStopped () {
0214     if (m_socket->state () == QSocket::Connected) {
0215         queueCommand (QString ("VOLU %1\n").arg (m_stored_volume).ascii ());
0216         queueCommand ("QUIT\n");
0217     }
0218 }
0219 
0220 KDE_NO_EXPORT void KMPlayerVDRSource::processStarted () {
0221     m_socket->connectToHost ("127.0.0.1", tcp_port);
0222     commands = new VDRCommand ("connect", commands);
0223 }
0224 
0225 #define DEF_ACT(i,text,pix,scut,slot,name) \
0226     m_actions [i] = new KAction (text, QString (pix), KShortcut (scut), this, slot, m_app->actionCollection (), name); \
0227     m_fullscreen_actions [i] = new KAction (text, KShortcut (scut), this, slot, m_app->view ()->viewArea ()->actionCollection (), name)
0228 
0229 KDE_NO_EXPORT void KMPlayerVDRSource::connected () {
0230     queueCommand (cmd_list_channels);
0231     queueCommand (cmd_volume_query);
0232     killTimer (channel_timer);
0233     channel_timer = startTimer (3000);
0234     KAction * action = m_app->actionCollection ()->action ("vdr_connect");
0235     action->setIcon (QString ("network-disconnect"));
0236     action->setText (i18n ("Dis&connect"));
0237     DEF_ACT (act_up, i18n ("VDR Key Up"), "go-up", , SLOT (keyUp ()), "vdr_key_up");
0238     DEF_ACT (act_down, i18n ("VDR Key Down"), "go-down", , SLOT (keyDown ()), "vdr_key_down");
0239     DEF_ACT (act_back, i18n ("VDR Key Back"), "go-previous", , SLOT (keyBack ()), "vdr_key_back");
0240     DEF_ACT (act_ok, i18n ("VDR Key Ok"), "dialog-ok", , SLOT (keyOk ()), "vdr_key_ok");
0241     DEF_ACT (act_setup, i18n ("VDR Key Setup"), "configure", , SLOT (keySetup ()), "vdr_key_setup");
0242     DEF_ACT (act_channels, i18n ("VDR Key Channels"), "view-media-playlist", , SLOT (keyChannels ()), "vdr_key_channels");
0243     DEF_ACT (act_menu, i18n ("VDR Key Menu"), "show-menu", , SLOT (keyMenu ()), "vdr_key_menu");
0244     DEF_ACT (act_red, i18n ("VDR Key Red"), "red", , SLOT (keyRed ()), "vdr_key_red");
0245     DEF_ACT (act_green, i18n ("VDR Key Green"), "green", , SLOT (keyGreen ()), "vdr_key_green");
0246     DEF_ACT (act_yellow, i18n ("VDR Key Yellow"), "yellow", , SLOT (keyYellow ()), "vdr_key_yellow");
0247     DEF_ACT (act_blue, i18n ("VDR Key Blue"), "blue", , SLOT (keyBlue ()), "vdr_key_blue");
0248     DEF_ACT (act_custom, "VDR Custom Command", "system-run", , SLOT (customCmd ()), "vdr_key_custom");
0249     m_app->initMenu (); // update menu and toolbar
0250     DEF_ACT (act_0, i18n ("VDR Key 0"), "0", Qt::Key_0, SLOT (key0 ()), "vdr_key_0");
0251     DEF_ACT (act_1, i18n ("VDR Key 1"), "1", Qt::Key_1, SLOT (key1 ()), "vdr_key_1");
0252     DEF_ACT (act_2, i18n ("VDR Key 2"), "2", Qt::Key_2, SLOT (key2 ()), "vdr_key_2");
0253     DEF_ACT (act_3, i18n ("VDR Key 3"), "3", Qt::Key_3, SLOT (key3 ()), "vdr_key_3");
0254     DEF_ACT (act_4, i18n ("VDR Key 4"), "4", Qt::Key_4, SLOT (key4 ()), "vdr_key_4");
0255     DEF_ACT (act_5, i18n ("VDR Key 5"), "5", Qt::Key_5, SLOT (key5 ()), "vdr_key_5");
0256     DEF_ACT (act_6, i18n ("VDR Key 6"), "6", Qt::Key_6, SLOT (key6 ()), "vdr_key_6");
0257     DEF_ACT (act_7, i18n ("VDR Key 7"), "7", Qt::Key_7, SLOT (key7 ()), "vdr_key_7");
0258     DEF_ACT (act_8, i18n ("VDR Key 8"), "8", Qt::Key_8, SLOT (key8 ()), "vdr_key_8");
0259     DEF_ACT (act_9, i18n ("VDR Key 9"), "9", Qt::Key_9, SLOT (key9 ()), "vdr_key_9");
0260     //KMPlayer::ViewLayer * layer = m_app->view ()->viewArea ();
0261     for (int i = 0; i < int (act_last); ++i)
0262         // somehow, the configured shortcuts only show up after createGUI() call
0263         m_fullscreen_actions [i]->setShortcut (m_actions [i]->shortcut ());
0264     //    m_fullscreen_actions[i]->plug (layer);
0265 }
0266 
0267 #undef DEF_ACT
0268 
0269 KDE_NO_EXPORT void KMPlayerVDRSource::disconnected () {
0270     kdDebug() << "disconnected " << commands << endl;
0271     if (finish_timer) {
0272         deleteCommands ();
0273         return;
0274     }
0275     setUrl (QString ("vdr://localhost:%1").arg (tcp_port));
0276     if (channel_timer && m_player->source () == this)
0277         m_player->stop ();
0278     deleteCommands ();
0279     KAction * action = m_app->actionCollection ()->action ("vdr_connect");
0280     action->setIcon (QString ("network-connect"));
0281     action->setText (i18n ("&Connect"));
0282     m_app->guiFactory ()->removeClient (m_app);// crash w/ m_actions[i]->unplugAll (); in for loop below
0283     for (int i = 0; i < int (act_last); ++i)
0284         if (m_player->view () && m_actions[i]) {
0285             m_fullscreen_actions[i]->unplug (m_app->view()->viewArea());
0286             delete m_actions[i];
0287             delete m_fullscreen_actions[i];
0288         }
0289     m_app->initMenu ();
0290 }
0291 
0292 KDE_NO_EXPORT void KMPlayerVDRSource::toggleConnected () {
0293     if (m_socket->state () == QSocket::Connected) {
0294         queueCommand ("QUIT\n");
0295         killTimer (channel_timer);
0296         channel_timer = 0;
0297     } else {
0298         m_socket->connectToHost ("127.0.0.1", tcp_port);
0299         commands = new VDRCommand ("connect", commands);
0300     }
0301 }
0302 
0303 KDE_NO_EXPORT void KMPlayerVDRSource::volumeChanged (int val) {
0304     queueCommand (QString ("VOLU %1\n").arg (int (sqrt (255 * 255 * val / 100))).ascii ());
0305 }
0306 
0307 static struct ReadBuf {
0308     char * buf;
0309     int length;
0310     KDE_NO_CDTOR_EXPORT ReadBuf () : buf (0L), length (0) {}
0311     KDE_NO_CDTOR_EXPORT ~ReadBuf () {
0312         clear ();
0313     }
0314     KDE_NO_EXPORT void operator += (const char * s) {
0315         int l = strlen (s);
0316         char * b = new char [length + l + 1];
0317         if (length)
0318             strcpy (b, buf);
0319         strcpy (b + length, s);
0320         length += l;
0321         delete buf;
0322         buf = b;
0323     }
0324     KDE_NO_EXPORT QCString mid (int p) {
0325         return QCString (buf + p);
0326     }
0327     KDE_NO_EXPORT QCString left (int p) {
0328         return QCString (buf, p);
0329     }
0330     KDE_NO_EXPORT QCString getReadLine ();
0331     KDE_NO_EXPORT void clear () {
0332         delete [] buf;
0333         buf = 0;
0334         length = 0;
0335     }
0336 } readbuf;
0337 
0338 KDE_NO_EXPORT QCString ReadBuf::getReadLine () {
0339     QCString out;
0340     if (!length)
0341         return out;
0342     int p = strcspn (buf, "\r\n");
0343     if (p < length) {
0344         int skip = strspn (buf + p, "\r\n");
0345         out = left (p+1);
0346         int nl = length - p - skip;
0347         memmove (buf, buf + p + skip, nl + 1);
0348         length = nl;
0349     }
0350     return out;
0351 }
0352 
0353 KDE_NO_EXPORT void KMPlayerVDRSource::readyRead () {
0354     KMPlayer::View * v = finish_timer ? 0L : static_cast <KMPlayer::View *> (m_player->view ());
0355     long nr = m_socket->bytesAvailable();
0356     char * data = new char [nr + 1];
0357     m_socket->readBlock (data, nr);
0358     data [nr] = 0;
0359     readbuf += data;
0360     QCString line = readbuf.getReadLine ();
0361     if (commands) {
0362         bool cmd_done = false;
0363         while (!line.isEmpty ()) {
0364             bool toconsole = true;
0365             cmd_done = (line.length () > 3 && line[3] == ' '); // from svdrpsend.pl
0366             // kdDebug () << "readyRead " << cmd_done << " " << commands->command << endl;
0367             if (!strcmp (commands->command, cmd_list_channels) && m_document) {
0368                 int p = line.find (';');
0369                 int q = line.find (':');
0370                 if (q > 0 && (p < 0 || q < p))
0371                     p = q;
0372                 if (p > 0)
0373                     line.truncate (p);
0374                 QString channel_name = line.mid (4);
0375                 m_document->appendChild (new KMPlayer::GenericMrl (m_document, QString ("kmplayer://vdrsource/%1").arg(channel_name), channel_name));
0376                 if (cmd_done) {
0377                     m_player->updateTree ();
0378                     if (!m_request_jump.isEmpty ()) {
0379                         jump (m_request_jump);
0380                         m_request_jump.truncate (0);
0381                     }
0382                 }
0383                 toconsole = false;
0384             } else if (!strcmp (commands->command, cmd_chan_query)) {
0385                 if (v && line.length () > 4) {
0386                     QString ch = line.mid (4);
0387                     setTitle (ch);
0388                     KMPlayer::PlayListItem * lvi = static_cast <KMPlayer::PlayListItem *> (v->playList ()->findItem (ch, 0));
0389                     if (lvi && lvi->node != m_last_channel) {
0390                         KMPlayer::PlayListItem * si = static_cast <KMPlayer::PlayListItem *> (v->playList ()->selectedItem ());
0391                         bool jump_selection = (si && (si->node == m_document || si->node == m_last_channel));
0392                         if (m_last_channel)
0393                             m_last_channel->setState (KMPlayer::Node::state_finished);
0394                         m_last_channel = lvi->node;
0395                         if (m_last_channel)
0396                             m_last_channel->setState (KMPlayer::Node::state_began);
0397                         if (jump_selection) {
0398                             v->playList ()->setSelected (lvi, true);
0399                             v->playList ()->ensureItemVisible (lvi);
0400                         }
0401                         v->playList ()->triggerUpdate ();
0402                     }
0403                     //v->playList ()->selectItem (ch);
0404                     int c = strtol(ch.ascii(), 0L, 10);
0405                     if (c != last_channel) {
0406                         last_channel = c;
0407                         m_app->statusBar ()->changeItem (QString::number (c),
0408                                                          id_status_timer);
0409                     }
0410                 }
0411             } else if (cmd_done && !strcmp(commands->command,cmd_volume_query)){
0412                 int pos = line.lastIndexOf (QChar (' '));
0413                 if (pos > 0) {
0414                     QString vol = line.mid (pos + 1);
0415                     if (!vol.compare ("mute"))
0416                         m_stored_volume = 0;
0417                     else
0418                         m_stored_volume = vol.toInt ();
0419                     if (m_stored_volume == 0)
0420                         volumeChanged (m_app->view ()->controlPanel ()->volumeBar ()->value ());
0421                 }
0422             }
0423             if (v && toconsole)
0424                 v->addText (QString (line), true);
0425             line = readbuf.getReadLine ();
0426         }
0427         if (cmd_done) {
0428             VDRCommand * c = commands->next;
0429             delete commands;
0430             commands = c;
0431             if (commands)
0432                 sendCommand ();
0433             else {
0434                 killTimer (timeout_timer);
0435                 timeout_timer = 0;
0436             }
0437         }
0438     }
0439     delete [] data;
0440 }
0441 
0442 KDE_NO_EXPORT void KMPlayerVDRSource::socketError (int code) {
0443     if (code == QSocket::ErrHostNotFound) {
0444         KMessageBox::error (m_configpage, i18n ("Host not found"), i18n ("Error"));
0445     } else if (code == QSocket::ErrConnectionRefused) {
0446         KMessageBox::error (m_configpage, i18n ("Connection refused"), i18n ("Error"));
0447     }
0448 }
0449 
0450 KDE_NO_EXPORT void KMPlayerVDRSource::queueCommand (const char * cmd) {
0451     if (m_player->source () != this)
0452         return;
0453     if (!commands) {
0454         readbuf.clear ();
0455         commands = new VDRCommand (cmd);
0456         if (m_socket->state () == QSocket::Connected) {
0457             sendCommand ();
0458         } else {
0459             m_socket->connectToHost ("127.0.0.1", tcp_port);
0460             commands = new VDRCommand ("connect", commands);
0461         }
0462     } else {
0463         VDRCommand * c = commands;
0464         for (int i = 0; i < 10; ++i, c = c->next)
0465             if (!c->next) {
0466                 c->next = new VDRCommand (cmd);
0467                 break;
0468             }
0469     }
0470 }
0471 
0472 KDE_NO_EXPORT void KMPlayerVDRSource::queueCommand (const char * cmd, int t) {
0473     queueCommand (cmd);
0474     killTimer (channel_timer);
0475     channel_timer = startTimer (t);
0476 }
0477 
0478 KDE_NO_EXPORT void KMPlayerVDRSource::sendCommand () {
0479     //kdDebug () << "sendCommand " << commands->command << endl;
0480     m_socket->writeBlock (commands->command, strlen(commands->command));
0481     m_socket->flush ();
0482     killTimer (timeout_timer);
0483     timeout_timer = startTimer (30000);
0484 }
0485 
0486 KDE_NO_EXPORT void KMPlayerVDRSource::customCmd () {
0487     QString cmd = KInputDialog::getText (i18n ("Custom VDR command"), i18n ("You can pass commands to VDR.\nEnter 'HELP' to see a list of available commands.\nYou can see VDR response in the console window.\n\nVDR Command:"), QString(), 0, m_player->view ());
0488     if (!cmd.isEmpty ())
0489         queueCommand (QString (cmd + QChar ('\n')).local8Bit ());
0490 }
0491 
0492 KDE_NO_EXPORT void KMPlayerVDRSource::timerEvent (QTimerEvent * e) {
0493     if (e->timerId () == timeout_timer || e->timerId () == finish_timer) {
0494         deleteCommands ();
0495     } else if (e->timerId () == channel_timer) {
0496         queueCommand (cmd_chan_query);
0497         killTimer (channel_timer);
0498         channel_timer = startTimer (30000);
0499     }
0500 }
0501 
0502 KDE_NO_EXPORT void KMPlayerVDRSource::deleteCommands () {
0503     killTimer (timeout_timer);
0504     timeout_timer = 0;
0505     killTimer (channel_timer);
0506     channel_timer = 0;
0507     for (VDRCommand * c = commands; c; c = commands) {
0508         commands = commands->next;
0509         delete c;
0510     }
0511     readbuf.clear ();
0512     if (finish_timer) {
0513         killTimer (finish_timer);
0514         QApplication::eventLoop ()->exitLoop ();
0515     }
0516 }
0517 
0518 KDE_NO_EXPORT void KMPlayerVDRSource::play (KMPlayer::Mrl *mrl) {
0519     if (!mrl || !mrl->isPlayable ()) return;
0520     jump (mrl->pretty_name);
0521 }
0522 
0523 KDE_NO_EXPORT void KMPlayerVDRSource::jump (const QString & channel) {
0524     QCString c ("CHAN ");
0525     QCString ch = channel.local8Bit ();
0526     int p = ch.find (' ');
0527     if (p > 0)
0528         c += ch.left (p);
0529     else
0530         c += ch; // hope for the best ..
0531     c += '\n';
0532     queueCommand (c);
0533 }
0534 
0535 KDE_NO_EXPORT void KMPlayerVDRSource::forward () {
0536     queueCommand ("CHAN +\n", 1000);
0537 }
0538 
0539 KDE_NO_EXPORT void KMPlayerVDRSource::backward () {
0540     queueCommand ("CHAN -\n", 1000);
0541 }
0542 
0543 KDE_NO_EXPORT void KMPlayerVDRSource::keyUp () {
0544     queueCommand ("HITK UP\n", 1000);
0545 }
0546 
0547 KDE_NO_EXPORT void KMPlayerVDRSource::keyDown () {
0548     queueCommand ("HITK DOWN\n", 1000);
0549 }
0550 
0551 KDE_NO_EXPORT void KMPlayerVDRSource::keyBack () {
0552     queueCommand ("HITK BACK\n");
0553 }
0554 
0555 KDE_NO_EXPORT void KMPlayerVDRSource::keyOk () {
0556     queueCommand ("HITK OK\n");
0557 }
0558 
0559 KDE_NO_EXPORT void KMPlayerVDRSource::keySetup () {
0560     queueCommand ("HITK SETUP\n");
0561 }
0562 
0563 KDE_NO_EXPORT void KMPlayerVDRSource::keyChannels () {
0564     queueCommand ("HITK CHANNELS\n");
0565 }
0566 
0567 KDE_NO_EXPORT void KMPlayerVDRSource::keyMenu () {
0568     queueCommand ("HITK MENU\n");
0569 }
0570 
0571 KDE_NO_EXPORT void KMPlayerVDRSource::key0 () {
0572     queueCommand ("HITK 0\n", 2000);
0573 }
0574 
0575 KDE_NO_EXPORT void KMPlayerVDRSource::key1 () {
0576     queueCommand ("HITK 1\n", 2000);
0577 }
0578 
0579 KDE_NO_EXPORT void KMPlayerVDRSource::key2 () {
0580     queueCommand ("HITK 2\n", 2000);
0581 }
0582 
0583 KDE_NO_EXPORT void KMPlayerVDRSource::key3 () {
0584     queueCommand ("HITK 3\n", 2000);
0585 }
0586 
0587 KDE_NO_EXPORT void KMPlayerVDRSource::key4 () {
0588     queueCommand ("HITK 4\n", 2000);
0589 }
0590 
0591 KDE_NO_EXPORT void KMPlayerVDRSource::key5 () {
0592     queueCommand ("HITK 5\n", 2000);
0593 }
0594 
0595 KDE_NO_EXPORT void KMPlayerVDRSource::key6 () {
0596     queueCommand ("HITK 6\n", 2000);
0597 }
0598 
0599 KDE_NO_EXPORT void KMPlayerVDRSource::key7 () {
0600     queueCommand ("HITK 7\n", 2000);
0601 }
0602 
0603 KDE_NO_EXPORT void KMPlayerVDRSource::key8 () {
0604     queueCommand ("HITK 8\n", 2000);
0605 }
0606 
0607 KDE_NO_EXPORT void KMPlayerVDRSource::key9 () {
0608     queueCommand ("HITK 9\n", 2000);
0609 }
0610 
0611 KDE_NO_EXPORT void KMPlayerVDRSource::keyRed () {
0612     queueCommand ("HITK RED\n");
0613 }
0614 
0615 KDE_NO_EXPORT void KMPlayerVDRSource::keyGreen () {
0616     queueCommand ("HITK GREEN\n");
0617 }
0618 
0619 KDE_NO_EXPORT void KMPlayerVDRSource::keyYellow () {
0620     queueCommand ("HITK YELLOW\n");
0621 }
0622 
0623 KDE_NO_EXPORT void KMPlayerVDRSource::keyBlue () {
0624     queueCommand ("HITK BLUE\n");
0625 }
0626 
0627 KDE_NO_EXPORT void KMPlayerVDRSource::write (KConfig * m_config) {
0628     m_config->setGroup (strVDR);
0629     m_config->writeEntry (strVDRPort, tcp_port);
0630     m_config->writeEntry (strXVPort, m_xvport);
0631     m_config->writeEntry (strXVEncoding, m_xvencoding);
0632     m_config->writeEntry (strXVScale, scale);
0633 }
0634 
0635 KDE_NO_EXPORT void KMPlayerVDRSource::read (KConfig * m_config) {
0636     m_config->setGroup (strVDR);
0637     tcp_port = m_config->readNumEntry (strVDRPort, 2001);
0638     m_xvport = m_config->readNumEntry (strXVPort, 0);
0639     m_xvencoding = m_config->readNumEntry (strXVEncoding, 0);
0640     scale = m_config->readNumEntry (strXVScale, 0);
0641 }
0642 
0643 struct XVTreeItem : public Q3ListViewItem {
0644     XVTreeItem (Q3ListViewItem *parent, const QString & t, int p, int e)
0645         : Q3ListViewItem (parent, t), port (p), encoding (e) {}
0646     int port;
0647     int encoding;
0648 };
0649 
0650 KDE_NO_EXPORT void KMPlayerVDRSource::sync (bool fromUI) {
0651     XvProcessInfo *pi = static_cast<XvProcessInfo *>(m_player->mediaManager()->
0652             processInfos()["xvideo"]);
0653     if (fromUI) {
0654         tcp_port = m_configpage->tcp_port->text ().toInt ();
0655         scale = m_configpage->scale->id (m_configpage->scale->selected ());
0656         setAspect (m_document, scale ? 16.0/9 : 1.25);
0657         XVTreeItem * vitem = dynamic_cast <XVTreeItem *> (m_configpage->xv_port->selectedItem ());
0658         if (vitem) {
0659             m_xvport = vitem->port;
0660             m_xvencoding = vitem->encoding;
0661         }
0662     } else {
0663         m_configpage->tcp_port->setText (QString::number (tcp_port));
0664         m_configpage->scale->setButton (scale);
0665         Q3ListViewItem * vitem = m_configpage->xv_port->firstChild ();
0666         NodePtr configdoc = pi->config_doc;
0667         if (configdoc && configdoc->firstChild ()) {
0668             for (Q3ListViewItem *i=vitem->firstChild(); i; i=vitem->firstChild())
0669                 delete i;
0670             NodePtr node = configdoc->firstChild ();
0671             for (node = node->firstChild (); node; node = node->nextSibling()) {
0672                 if (!node->isElementNode ())
0673                     continue; // some text sneaked in ?
0674                 Element * elm = convertNode <Element> (node);
0675                 if (elm->getAttribute (KMPlayer::StringPool::attr_type) !=
0676                         QString ("tree"))
0677                     continue;
0678                 for (NodePtr n = elm->firstChild (); n; n = n->nextSibling ()) {
0679                     if (!n->isElementNode () || strcmp (n->nodeName (), "Port"))
0680                         continue;
0681                     Element * e = convertNode <Element> (n);
0682                     QString portatt = e->getAttribute (
0683                             KMPlayer::StringPool::attr_value);
0684                     int port;
0685                     Q3ListViewItem *pi = new Q3ListViewItem (vitem, i18n ("Port ") + portatt);
0686                     port = portatt.toInt ();
0687                     for (NodePtr in=e->firstChild(); in; in=in->nextSibling()) {
0688                         if (!in->isElementNode () ||
0689                                 strcmp (in->nodeName (), "Input"))
0690                             continue;
0691                         Element * i = convertNode <Element> (in);
0692                         QString inp = i->getAttribute (
0693                                 KMPlayer::StringPool::attr_name);
0694                         int enc = i->getAttribute (
0695                                 KMPlayer::StringPool::attr_value).toInt ();
0696                         Q3ListViewItem * ii = new XVTreeItem(pi, inp, port, enc);
0697                         if (m_xvport == port && enc == m_xvencoding) {
0698                             ii->setSelected (true);
0699                             m_configpage->xv_port->ensureItemVisible (ii);
0700                         }
0701                     }
0702                 }
0703             }
0704         } else { // wait for showEvent
0705             connect(pi, SIGNAL(configReceived()), this, SLOT(configReceived()));
0706         }
0707     }
0708 }
0709 
0710 KDE_NO_EXPORT void KMPlayerVDRSource::configReceived () {
0711     XvProcessInfo *pi = static_cast<XvProcessInfo *>(m_player->mediaManager()->
0712             processInfos()["xvideo"]);
0713     disconnect (pi, SIGNAL (configReceived()), this, SLOT (configReceived()));
0714     sync (false);
0715 }
0716 
0717 KDE_NO_EXPORT void KMPlayerVDRSource::prefLocation (QString & item, QString & icon, QString & tab) {
0718     item = i18n ("Source");
0719     icon = QString ("source");
0720     tab = i18n ("VDR");
0721 }
0722 
0723 KDE_NO_EXPORT QFrame * KMPlayerVDRSource::prefPage (QWidget * parent) {
0724     if (!m_configpage)
0725         m_configpage = new KMPlayerPrefSourcePageVDR (parent, m_player);
0726     return m_configpage;
0727 }
0728 
0729 KDE_NO_EXPORT void KMPlayerVDRSource::stateElementChanged (KMPlayer::Node *, KMPlayer::Node::State, KMPlayer::Node::State) {
0730 }
0731 
0732 //-----------------------------------------------------------------------------
0733 
0734 static const char * xv_supported [] = {
0735     "tvsource", "vdrsource", 0L
0736 };
0737 
0738 XvProcessInfo::XvProcessInfo (MediaManager *mgr)
0739  : CallbackProcessInfo ("xvideo", i18n ("X&Video"), xv_supported, mgr, NULL) {}
0740 
0741 IProcess *XvProcessInfo::create (PartBase *part, AudioVideoMedia *media) {
0742     XVideo *x = new XVideo (part, this, part->settings ());
0743     x->setSource (part->source ());
0744     x->media_object = media;
0745     part->processCreated (x);
0746     return x;
0747 }
0748 
0749 bool XvProcessInfo::startBackend () {
0750     if (m_process && m_process->isRunning ())
0751         return true;
0752     Settings *cfg = manager->player ()->settings();
0753 
0754     initProcess ();
0755 
0756     QString cmd  = QString ("kxvplayer -cb %1").arg (dcopName ());
0757     if (have_config == config_unknown || have_config == config_probe)
0758         cmd += QString (" -c");
0759     //if (m_source) {
0760     //    int xv_port = m_source->xvPort ();
0761     //    int xv_encoding = m_source->xvEncoding ();
0762     //    int freq = m_source->frequency ();
0763     //    cmd += QString (" -port %1 -enc %2 -norm \"%3\"").arg (xv_port).arg (xv_encoding).arg (m_source->videoNorm ());
0764     //    if (freq > 0)
0765     //        cmd += QString (" -freq %1").arg (freq);
0766     //}
0767     fprintf (stderr, "%s\n", cmd.latin1 ());
0768     *m_process << cmd;
0769     m_process->start (KProcess::NotifyOnExit, KProcess::All);
0770 
0771     return m_process->isRunning ();
0772 }
0773 
0774 KDE_NO_CDTOR_EXPORT XVideo::XVideo (QObject *p, ProcessInfo *pi, Settings *s)
0775  : KMPlayer::CallbackProcess (p, pi, s, "xvideo") {
0776     //m_player->settings ()->addPage (m_configpage);
0777 }
0778 
0779 KDE_NO_CDTOR_EXPORT XVideo::~XVideo () {}
0780 
0781 KDE_NO_EXPORT bool XVideo::ready () {
0782     if (running () || !media_object || !media_object->viewer) {
0783         setState (IProcess::Ready);
0784         return true;
0785     }
0786     return static_cast <XvProcessInfo *> (process_info)->startBackend ();
0787 }
0788 
0789 #include "kmplayervdr.moc"