/*************************************************************************** Interface to access JuK ------------------- begin : Mon Jan 15 21:09:00 CEST 2001 copyright : (C) 2001-2002 by Stefan Gehn email : metz {AT} gehn {DOT} net ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "jukInterface.h" #include "jukInterface.moc" #include #include #include #include #include #include #define TIMER_FAST 250 JuKInterface::JuKInterface() : PlayerInterface(), mProc(0) { mTimerValue = TIMER_FAST; mJuKTimer = new TQTimer ( this, "mJukTimer" ); connect(mJuKTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateSlider()) ); kapp->dcopClient()->setNotifications ( true ); connect(kapp->dcopClient(), TQT_SIGNAL(applicationRegistered(const TQCString&)), TQT_SLOT(appRegistered(const TQCString&)) ); connect(kapp->dcopClient(), TQT_SIGNAL(applicationRemoved(const TQCString&)), TQT_SLOT(appRemoved(const TQCString&))); TQTimer::singleShot(0, this, TQT_SLOT(myInit())); } JuKInterface::~JuKInterface() { kapp->dcopClient()->setNotifications(false); delete mJuKTimer; } void JuKInterface::myInit() { // Start the timer if juk is already running // Needed if user adds applet while running juk if ( findRunningJuK() ) { emit playerStarted(); mJuKTimer->start(mTimerValue); } else { emit playerStopped(); emit newSliderPosition(0,0); } } void JuKInterface::appRegistered ( const TQCString &appId ) { if(appId.contains("juk",false) ) { mAppId = appId; // BWAHAHAHA EVIL HACK // JuK blocks DCOP signals on its startup, so if we try to // ping it now, it'll simply cause us to block, which will // cause kicker to block, which is bad, m'kay? // // So what we do is launch the dcop command instead, and let // *it* block for us. As soon as the command exits, we know // that JuK is ready to go (and so are we). mProc = new TQProcess(this, "jukdcopCheckProc"); mProc->addArgument("dcop"); mProc->addArgument("juk"); mProc->addArgument("Player"); mProc->addArgument("status()"); connect(mProc, TQT_SIGNAL(processExited()), TQT_SLOT(jukIsReady())); mProc->start(); } } void JuKInterface::appRemoved ( const TQCString &appId ) { if ( appId.contains("juk",false) ) { // is there still another juk alive? if ( findRunningJuK() ) return; mJuKTimer->stop(); emit playerStopped(); emit newSliderPosition(0,0); } } /* Called when the dcop process we launch terminates */ void JuKInterface::jukIsReady() { emit playerStarted(); mJuKTimer->start(mTimerValue); mProc->deleteLater(); mProc = 0; } void JuKInterface::updateSlider () { // length/time in msecs, -1 means "no playobject in juk" int len = -1; int time = -1; TQByteArray data, replyData; TQCString replyType; if (kapp->dcopClient()->call(mAppId, "Player", "totalTime()", data, replyType, replyData)) { TQDataStream reply(replyData, IO_ReadOnly); if (replyType == "int") reply >> len; } data = 0; replyData = 0; replyType = 0; if (kapp->dcopClient()->call(mAppId, "Player", "currentTime()", data, replyType, replyData)) { TQDataStream reply(replyData, IO_ReadOnly); if (replyType == "int") reply >> time; } if ( (time < 0) || (len < 0)) // JuK isn't playing and thus returns -1 { len = 0; time = 0; } emit ( newSliderPosition(len,time) ); emit playingStatusChanged(playingStatus()); } // Drag-n-Drop stuff ================================================================= void JuKInterface::dragEnterEvent(TQDragEnterEvent* event) { // kdDebug(90200) << "JuKInterface::dragEnterEvent()" << endl; event->accept( KURLDrag::canDecode(event) ); } void JuKInterface::dropEvent(TQDropEvent* event) { // kdDebug(90200) << "JuKInterface::dropEvent()" << endl; KURL::List list; if (KURLDrag::decode(event, list)) { TQByteArray data, replyData; TQStringList fileList; TQCString replyType; TQDataStream arg(data, IO_WriteOnly); // Juk doesn't handle KURL's yet, so we need to form a list // that contains the local paths. for (KURL::List::ConstIterator it = list.begin(); it != list.end(); ++it) fileList += (*it).path(); arg << fileList << false; // Use call instead of send to make sure the files are added // before we try to play. if (!kapp->dcopClient()->call(mAppId, "Collection", "openFile(TQStringList)", data, replyType, replyData, true)) { kdDebug(90200) << "Couldn't send drop to juk" << endl; } // Apparently we should auto-play? TQByteArray strData; TQDataStream strArg(strData, IO_WriteOnly); strArg << *fileList.begin(); if (!kapp->dcopClient()->send(mAppId, "Player", "play(TQString)", strData)) kdDebug(90200) << "Couldn't send play command to juk" << endl; } } // ==================================================================================== void JuKInterface::sliderStartDrag() { mJuKTimer->stop(); } void JuKInterface::sliderStopDrag() { mJuKTimer->start(mTimerValue); } void JuKInterface::jumpToTime( int sec ) { TQByteArray data; TQDataStream arg(data, IO_WriteOnly); arg << sec; // Used in JuK shipping with KDE < 3.3 //kapp->dcopClient()->send(mAppId, "Player", "setTime(int)", data); kapp->dcopClient()->send(mAppId, "Player", "seek(int)", data); } void JuKInterface::playpause() { if (!findRunningJuK()) startPlayer("juk"); TQByteArray data; kapp->dcopClient()->send(mAppId, "Player", "playPause()", data); } void JuKInterface::stop() { TQByteArray data; kapp->dcopClient()->send(mAppId, "Player", "stop()", data); } void JuKInterface::next() { TQByteArray data; kapp->dcopClient()->send(mAppId, "Player", "forward()", data); } void JuKInterface::prev() { TQByteArray data; kapp->dcopClient()->send(mAppId, "Player", "back()", data); } void JuKInterface::volumeUp() { TQByteArray data; kapp->dcopClient()->send(mAppId, "Player", "volumeUp()", data); } void JuKInterface::volumeDown() { TQByteArray data; kapp->dcopClient()->send(mAppId, "Player", "volumeDown()", data); } const TQString JuKInterface::getTrackTitle() const { TQString title; TQByteArray data, replyData; TQCString replyType; if (kapp->dcopClient()->call(mAppId, "Player", "playingString()",data, replyType, replyData)) { TQDataStream reply(replyData, IO_ReadOnly); if (replyType == TQSTRING_OBJECT_NAME_STRING) { reply >> title; return title; } } return TQString(""); } // FIXME: what if we have a dcop app named, let's say, 'jukfrontend'? bool JuKInterface::findRunningJuK() { QCStringList allApps = kapp->dcopClient()->registeredApplications(); TQValueList::const_iterator iterator; for (iterator = allApps.constBegin(); iterator != allApps.constEnd(); ++iterator) { if ((*iterator).contains("juk",false)) { mAppId = *iterator; return true; } } return false; } int JuKInterface::playingStatus() { TQByteArray data, replyData; TQCString replyType; if (kapp->dcopClient()->call(mAppId, "Player", "status()", data, replyType, replyData)) { int status = 0; TQDataStream reply(replyData, IO_ReadOnly); if (replyType == "int") reply >> status; if (status == 2) return Playing; else if (status == 1) return Paused; } return Stopped; }