|
|
|
/*
|
|
|
|
Copyright (c) 1997 Christian Esken (esken@kde.org)
|
|
|
|
2000 Charles Samuels (charles@kde.org)
|
|
|
|
2000 Stefan Schimanski (1Stein@gmx.de)
|
|
|
|
2000 Matthias Ettrich (ettrich@kde.org)
|
|
|
|
2000 Waldo Bastian <bastian@kde.org>
|
|
|
|
2000-2003 Carsten Pfeiffer <pfeiffer@kde.org>
|
|
|
|
|
|
|
|
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, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// C headers
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
// aRts headers
|
|
|
|
#include <connect.h>
|
|
|
|
#include <dispatcher.h>
|
|
|
|
#include <flowsystem.h>
|
|
|
|
#include <qiomanager.h>
|
|
|
|
#include <soundserver.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// QT headers
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
|
|
|
|
// KDE headers
|
|
|
|
#include <dcopclient.h>
|
|
|
|
#include <tdeaboutdata.h>
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
#include <kartsdispatcher.h>
|
|
|
|
#include <kartsserver.h>
|
|
|
|
#endif
|
|
|
|
#include <tdecmdlineargs.h>
|
|
|
|
#include <tdeconfig.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tdeglobal.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <kpassivepopup.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kmacroexpander.h>
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
#include <kplayobjectfactory.h>
|
|
|
|
#include <kaudiomanagerplay.h>
|
|
|
|
#endif
|
|
|
|
#include <kprocess.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kuniqueapplication.h>
|
|
|
|
#include <twin.h>
|
|
|
|
|
|
|
|
#include "knotify.h"
|
|
|
|
#include "knotify.moc"
|
|
|
|
|
|
|
|
class KNotifyPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TDEConfig* globalEvents;
|
|
|
|
TDEConfig* globalConfig;
|
|
|
|
TQMap<TQString, TDEConfig*> events;
|
|
|
|
TQMap<TQString, TDEConfig*> configs;
|
|
|
|
TQString externalPlayer;
|
|
|
|
TDEProcess *externalPlayerProc;
|
|
|
|
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
TQPtrList<KDE::PlayObject> playObjects;
|
|
|
|
TQMap<KDE::PlayObject*,int> playObjectEventMap;
|
|
|
|
KAudioManagerPlay *audioManager;
|
|
|
|
#endif
|
|
|
|
int externalPlayerEventId;
|
|
|
|
|
|
|
|
bool useExternal;
|
|
|
|
bool useArts;
|
|
|
|
int volume;
|
|
|
|
TQTimer *playTimer;
|
|
|
|
bool inStartup;
|
|
|
|
TQString startupEvents;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Yes, it's ugly to put this here, but this facilitates the cautious startup
|
|
|
|
// procedure.
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
KArtsServer *soundServer = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern "C"{
|
|
|
|
KDE_EXPORT int kdemain(int argc, char **argv) {
|
|
|
|
TDEAboutData aboutdata("knotify", I18N_NOOP("KNotify"),
|
|
|
|
"3.0", I18N_NOOP("TDE Notification Server"),
|
|
|
|
TDEAboutData::License_GPL, "(C) 1997-2003, KDE Developers");
|
|
|
|
aboutdata.addAuthor("Carsten Pfeiffer",I18N_NOOP("Current Maintainer"),"pfeiffer@kde.org");
|
|
|
|
aboutdata.addAuthor("Christian Esken",0,"esken@kde.org");
|
|
|
|
aboutdata.addAuthor("Stefan Westerfeld",I18N_NOOP("Sound support"),"stefan@space.twc.de");
|
|
|
|
aboutdata.addAuthor("Charles Samuels",I18N_NOOP("Previous Maintainer"),"charles@kde.org");
|
|
|
|
|
|
|
|
TDECmdLineArgs::init( argc, argv, &aboutdata );
|
|
|
|
KUniqueApplication::addCmdLineOptions();
|
|
|
|
|
|
|
|
// initialize application
|
|
|
|
if ( !KUniqueApplication::start() ) {
|
|
|
|
kdDebug() << "Running knotify found" << endl;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
KUniqueApplication app;
|
|
|
|
app.disableSessionManagement();
|
|
|
|
|
|
|
|
// KNotify is started on KDE startup and on demand (using
|
|
|
|
// KNotifClient::startDaemon()) whenever a KNotify event occurs. Especially
|
|
|
|
// KWin may fire many events (e.g. when a window pops up). When we have
|
|
|
|
// problems with aRts or the installation, we might get an infinite loop
|
|
|
|
// of knotify crashing, popping up the crashhandler window and twin firing
|
|
|
|
// another event, starting knotify again...
|
|
|
|
// We try to prevent this by tracking our startup and offer options to
|
|
|
|
// abort this.
|
|
|
|
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
TDEConfigGroup config( TDEGlobal::config(), "StartProgress" );
|
|
|
|
TDEConfig artsKCMConfig( "kcmartsrc" );
|
|
|
|
artsKCMConfig.setGroup( "Arts" );
|
|
|
|
bool useArts = artsKCMConfig.readBoolEntry( "StartServer", true );
|
|
|
|
if (useArts) {
|
|
|
|
useArts = config.readBoolEntry( "Use Arts", useArts );
|
|
|
|
}
|
|
|
|
bool ok = config.readBoolEntry( "Arts Init", true );
|
|
|
|
|
|
|
|
if ( useArts && !ok ) {
|
|
|
|
if ( KMessageBox::questionYesNo(
|
|
|
|
0L,
|
|
|
|
i18n("During the previous startup, KNotify crashed while creating "
|
|
|
|
"Arts::Dispatcher. Do you want to try again or disable "
|
|
|
|
"aRts sound output?\n\n"
|
|
|
|
"If you choose to disable aRts output now, you can re-enable "
|
|
|
|
"it later or select an alternate sound player "
|
|
|
|
"in the System Notifications control panel."),
|
|
|
|
i18n("KNotify Problem"),
|
|
|
|
i18n("&Try Again"),
|
|
|
|
i18n("D&isable aRts Output"),
|
|
|
|
"KNotifyStartProgress",
|
|
|
|
0 /* don't call KNotify :) */
|
|
|
|
)
|
|
|
|
== KMessageBox::No ) {
|
|
|
|
useArts = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// when ArtsDispatcher crashes, we know it the next start.
|
|
|
|
config.writeEntry( "Arts Init", false );
|
|
|
|
config.writeEntry( "Use Arts", useArts );
|
|
|
|
config.sync();
|
|
|
|
|
|
|
|
KArtsDispatcher *dispatcher = 0;
|
|
|
|
if ( useArts ) {
|
|
|
|
dispatcher = new KArtsDispatcher;
|
|
|
|
soundServer = new KArtsServer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ok, seemed to work.
|
|
|
|
config.writeEntry("Arts Init", useArts );
|
|
|
|
config.sync();
|
|
|
|
|
|
|
|
ok = config.readBoolEntry( "KNotify Init", true );
|
|
|
|
if ( useArts && !ok ) {
|
|
|
|
if ( KMessageBox::questionYesNo(
|
|
|
|
0L,
|
|
|
|
i18n("During the previous startup, KNotify crashed while instantiating "
|
|
|
|
"KNotify. Do you want to try again or disable "
|
|
|
|
"aRts sound output?\n\n"
|
|
|
|
"If you choose to disable aRts output now, you can re-enable "
|
|
|
|
"it later or select an alternate sound player "
|
|
|
|
"in the System Notifications control panel."),
|
|
|
|
i18n("KNotify Problem"),
|
|
|
|
i18n("&Try Again"),
|
|
|
|
i18n("D&isable aRts Output"),
|
|
|
|
"KNotifyStartProgress",
|
|
|
|
0 /* don't call KNotify :) */
|
|
|
|
)
|
|
|
|
== KMessageBox::No ) {
|
|
|
|
useArts = false;
|
|
|
|
delete soundServer;
|
|
|
|
soundServer = 0L;
|
|
|
|
delete dispatcher;
|
|
|
|
dispatcher = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// when KNotify instantiation crashes, we know it the next start.
|
|
|
|
config.writeEntry( "KNotify Init", false );
|
|
|
|
config.writeEntry( "Use Arts", useArts );
|
|
|
|
config.sync();
|
|
|
|
|
|
|
|
// start notify service
|
|
|
|
KNotify *notify = new KNotify( useArts );
|
|
|
|
|
|
|
|
config.writeEntry( "KNotify Init", true );
|
|
|
|
config.sync();
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
// start notify service, without aRts
|
|
|
|
KNotify *notify = new KNotify( false );
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
app.dcopClient()->setDefaultObject( "Notify" );
|
|
|
|
app.dcopClient()->setDaemonMode( true );
|
|
|
|
// kdDebug() << "knotify starting" << endl;
|
|
|
|
|
|
|
|
int ret = app.exec();
|
|
|
|
delete notify;
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
delete soundServer;
|
|
|
|
delete dispatcher;
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} // end extern "C"
|
|
|
|
|
|
|
|
KNotify::KNotify( bool useArts )
|
|
|
|
: TQObject(), DCOPObject("Notify")
|
|
|
|
{
|
|
|
|
d = new KNotifyPrivate;
|
|
|
|
d->globalEvents = new TDEConfig("knotify/eventsrc", true, false, "data");
|
|
|
|
d->globalConfig = new TDEConfig("knotify.eventsrc", true, false);
|
|
|
|
d->externalPlayerProc = 0;
|
|
|
|
d->useArts = useArts;
|
|
|
|
d->inStartup = true;
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
d->playObjects.setAutoDelete(true);
|
|
|
|
d->audioManager = 0;
|
|
|
|
if( useArts ) {
|
|
|
|
connect( soundServer, TQT_SIGNAL( restartedServer() ), this, TQT_SLOT( restartedArtsd() ) );
|
|
|
|
restartedArtsd(); //started allready need to initialize d->audioManager
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
d->volume = 100;
|
|
|
|
d->playTimer = 0;
|
|
|
|
|
|
|
|
loadConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
KNotify::~KNotify()
|
|
|
|
{
|
|
|
|
reconfigure();
|
|
|
|
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
d->playObjects.clear();
|
|
|
|
|
|
|
|
delete d->globalEvents;
|
|
|
|
delete d->globalConfig;
|
|
|
|
delete d->externalPlayerProc;
|
|
|
|
delete d->audioManager;
|
|
|
|
#endif
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNotify::loadConfig() {
|
|
|
|
// load external player settings
|
|
|
|
TDEConfig *kc = TDEGlobal::config();
|
|
|
|
kc->setGroup("Misc");
|
|
|
|
d->useExternal = kc->readBoolEntry( "Use external player", false );
|
|
|
|
d->externalPlayer = kc->readPathEntry("External player");
|
|
|
|
|
|
|
|
// try to locate a suitable player if none is configured
|
|
|
|
if ( d->externalPlayer.isEmpty() ) {
|
|
|
|
TQStringList players;
|
|
|
|
players << "wavplay" << "aplay" << "auplay";
|
|
|
|
TQStringList::Iterator it = players.begin();
|
|
|
|
while ( d->externalPlayer.isEmpty() && it != players.end() ) {
|
|
|
|
d->externalPlayer = TDEStandardDirs::findExe( *it );
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// load default volume
|
|
|
|
d->volume = kc->readNumEntry( "Volume", 100 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNotify::reconfigure()
|
|
|
|
{
|
|
|
|
kapp->config()->reparseConfiguration();
|
|
|
|
loadConfig();
|
|
|
|
|
|
|
|
// clear loaded config files
|
|
|
|
d->globalConfig->reparseConfiguration();
|
|
|
|
for ( TQMapIterator<TQString,TDEConfig*> it = d->configs.begin(); it != d->configs.end(); ++it ) {
|
|
|
|
delete it.data();
|
|
|
|
}
|
|
|
|
d->configs.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNotify::notify(const TQString &event, const TQString &fromApp,
|
|
|
|
const TQString &text, TQString sound, TQString file,
|
|
|
|
int present, int level)
|
|
|
|
{
|
|
|
|
notify( event, fromApp, text, sound, file, present, level, 0, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::notify(const TQString &event, const TQString &fromApp,
|
|
|
|
const TQString &text, TQString sound, TQString file,
|
|
|
|
int present, int level, int winId)
|
|
|
|
{
|
|
|
|
notify( event, fromApp, text, sound, file, present, level, winId, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::notify(const TQString &event, const TQString &fromApp,
|
|
|
|
const TQString &text, TQString sound, TQString file,
|
|
|
|
int present, int level, int winId, int eventId )
|
|
|
|
{
|
|
|
|
// kdDebug() << "event=" << event << " fromApp=" << fromApp << " text=" << text << " sound=" << sound <<
|
|
|
|
// " file=" << file << " present=" << present << " level=" << level << " winId=" << winId << " eventId=" << eventId << endl;
|
|
|
|
if( d->inStartup ) {
|
|
|
|
d->startupEvents += "(" + event + ":" + fromApp + ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString commandline;
|
|
|
|
TDEConfig *eventsFile = NULL;
|
|
|
|
TDEConfig *configFile = NULL;
|
|
|
|
|
|
|
|
// check for valid events
|
|
|
|
if ( !event.isEmpty() ) {
|
|
|
|
|
|
|
|
// get config file
|
|
|
|
if ( d->events.contains( fromApp ) ) {
|
|
|
|
eventsFile = d->events[fromApp];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
eventsFile=new TDEConfig(locate("data", fromApp+"/eventsrc"),true,false);
|
|
|
|
d->events.insert( fromApp, eventsFile );
|
|
|
|
}
|
|
|
|
if ( d->configs.contains( fromApp) ) {
|
|
|
|
configFile = d->configs[fromApp];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
configFile=new TDEConfig(fromApp+".eventsrc",true,false);
|
|
|
|
d->configs.insert( fromApp, configFile );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !eventsFile->hasGroup( event ) && isGlobal(event) ) {
|
|
|
|
eventsFile = d->globalEvents;
|
|
|
|
configFile = d->globalConfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
eventsFile->setGroup( event );
|
|
|
|
configFile->setGroup( event );
|
|
|
|
|
|
|
|
// get event presentation
|
|
|
|
if ( present==-1 ) {
|
|
|
|
present = configFile->readNumEntry( "presentation", -1 );
|
|
|
|
}
|
|
|
|
if ( present==-1 ) {
|
|
|
|
present = eventsFile->readNumEntry( "default_presentation", 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// get sound file name
|
|
|
|
if( present & KNotifyClient::Sound ) {
|
|
|
|
TQString theSound = configFile->readPathEntry( "soundfile" );
|
|
|
|
if ( theSound.isEmpty() ) {
|
|
|
|
theSound = eventsFile->readPathEntry( "default_sound" );
|
|
|
|
}
|
|
|
|
if ( !theSound.isEmpty() ) {
|
|
|
|
sound = theSound;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get log file name
|
|
|
|
if( present & KNotifyClient::Logfile ) {
|
|
|
|
TQString theFile = configFile->readPathEntry( "logfile" );
|
|
|
|
if ( theFile.isEmpty() ) {
|
|
|
|
theFile = eventsFile->readPathEntry( "default_logfile" );
|
|
|
|
}
|
|
|
|
if ( !theFile.isEmpty() ) {
|
|
|
|
file = theFile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get default event level
|
|
|
|
if( present & KNotifyClient::Messagebox ) {
|
|
|
|
level = eventsFile->readNumEntry( "level", 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// get command line
|
|
|
|
if (present & KNotifyClient::Execute ) {
|
|
|
|
commandline = configFile->readPathEntry( "commandline" );
|
|
|
|
if ( commandline.isEmpty() ) {
|
|
|
|
commandline = eventsFile->readPathEntry( "default_commandline" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// emit event
|
|
|
|
if ( present & KNotifyClient::Sound ) { // && TQFile(sound).isReadable()
|
|
|
|
notifyBySound( sound, fromApp, eventId );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( present & KNotifyClient::Execute ) {
|
|
|
|
notifyByExecute( commandline, event, fromApp, text, winId, eventId );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( present & KNotifyClient::Logfile ) { // && TQFile(file).isWritable()
|
|
|
|
notifyByLogfile( text, file );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( present & KNotifyClient::Stderr ) {
|
|
|
|
notifyByStderr( text );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( present & KNotifyClient::Taskbar ) {
|
|
|
|
notifyByTaskbar( checkWinId( fromApp, winId ));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( present & KNotifyClient::PassivePopup ) {
|
|
|
|
notifyByPassivePopup( text, fromApp, eventsFile, checkWinId( fromApp, winId ));
|
|
|
|
}
|
|
|
|
else if ( present & KNotifyClient::Messagebox ) {
|
|
|
|
notifyByMessagebox( text, level, checkWinId( fromApp, winId ));
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray qbd;
|
|
|
|
TQDataStream ds(qbd, IO_WriteOnly);
|
|
|
|
ds << event << fromApp << text << sound << file << present << level << winId << eventId;
|
|
|
|
emitDCOPSignal("notifySignal(TQString,TQString,TQString,TQString,TQString,int,int,int,int)", qbd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KNotify::notifyBySound( const TQString &sound, const TQString &appname, int eventId )
|
|
|
|
{
|
|
|
|
if (sound.isEmpty()) {
|
|
|
|
soundFinished( eventId, NoSoundFile );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool external = d->useExternal && !d->externalPlayer.isEmpty();
|
|
|
|
// get file name
|
|
|
|
TQString soundFile(sound);
|
|
|
|
if ( TQFileInfo(sound).isRelative() ) {
|
|
|
|
TQString search = TQString("%1/sounds/%2").arg(appname).arg(sound);
|
|
|
|
soundFile = TDEGlobal::instance()->dirs()->findResource("data", search);
|
|
|
|
if ( soundFile.isEmpty() ) {
|
|
|
|
soundFile = locate( "sound", sound );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( soundFile.isEmpty() || isPlaying( soundFile ) ) {
|
|
|
|
soundFinished( eventId, soundFile.isEmpty() ? NoSoundFile : FileAlreadyPlaying );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// kdDebug() << "KNotify::notifyBySound - trying to play file " << soundFile << endl;
|
|
|
|
|
|
|
|
if (!external) {
|
|
|
|
//If we disabled using aRts, just return,
|
|
|
|
//(If we don't, we'll blow up accessing the null soundServer)
|
|
|
|
if (!d->useArts)
|
|
|
|
{
|
|
|
|
soundFinished( eventId, NoSoundSupport );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
// play sound finally
|
|
|
|
while( d->playObjects.count()>5 ) {
|
|
|
|
abortFirstPlayObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE::PlayObjectFactory factory(soundServer->server());
|
|
|
|
if( d->audioManager ) {
|
|
|
|
factory.setAudioManagerPlay( d->audioManager );
|
|
|
|
}
|
|
|
|
KURL soundURL;
|
|
|
|
soundURL.setPath(soundFile);
|
|
|
|
KDE::PlayObject *playObject = factory.createPlayObject(soundURL, false);
|
|
|
|
|
|
|
|
if (playObject->isNull()) {
|
|
|
|
soundFinished( eventId, NoSoundSupport );
|
|
|
|
delete playObject;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( d->volume != 100 ) {
|
|
|
|
// It works to access the playObject immediately because we don't allow
|
|
|
|
// non-file URLs for sounds.
|
|
|
|
Arts::StereoVolumeControl volumeControl = Arts::DynamicCast(soundServer->server().createObject("Arts::StereoVolumeControl"));
|
|
|
|
Arts::PlayObject player = playObject->object();
|
|
|
|
Arts::Synth_AMAN_PLAY ap = d->audioManager->amanPlay();
|
|
|
|
if( ! volumeControl.isNull() && ! player.isNull() && ! ap.isNull() ) {
|
|
|
|
volumeControl.scaleFactor( d->volume/100.0 );
|
|
|
|
|
|
|
|
ap.stop();
|
|
|
|
Arts::disconnect( player, "left", ap, "left" );
|
|
|
|
Arts::disconnect( player, "right", ap, "right" );
|
|
|
|
|
|
|
|
ap.start();
|
|
|
|
volumeControl.start();
|
|
|
|
|
|
|
|
Arts::connect(player,"left",volumeControl,"inleft");
|
|
|
|
Arts::connect(player,"right",volumeControl,"inright");
|
|
|
|
|
|
|
|
Arts::connect(volumeControl,"outleft",ap,"left");
|
|
|
|
Arts::connect(volumeControl,"outright",ap,"right");
|
|
|
|
|
|
|
|
player._addChild( volumeControl, "volume" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
playObject->play();
|
|
|
|
d->playObjects.append( playObject );
|
|
|
|
d->playObjectEventMap.insert( playObject, eventId );
|
|
|
|
|
|
|
|
if ( !d->playTimer ) {
|
|
|
|
d->playTimer = new TQTimer( this );
|
|
|
|
connect( d->playTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( playTimeout() ) );
|
|
|
|
}
|
|
|
|
if ( !d->playTimer->isActive() ) {
|
|
|
|
d->playTimer->start( 1000 );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if(!d->externalPlayer.isEmpty()) {
|
|
|
|
// use an external player to play the sound
|
|
|
|
TDEProcess *proc = d->externalPlayerProc;
|
|
|
|
if (!proc) {
|
|
|
|
proc = d->externalPlayerProc = new TDEProcess;
|
|
|
|
connect( proc, TQT_SIGNAL( processExited( TDEProcess * )), TQT_SLOT( slotPlayerProcessExited( TDEProcess * )));
|
|
|
|
}
|
|
|
|
if (proc->isRunning()) {
|
|
|
|
soundFinished( eventId, PlayerBusy );
|
|
|
|
return false; // Skip
|
|
|
|
}
|
|
|
|
proc->clearArguments();
|
|
|
|
(*proc) << d->externalPlayer << TQFile::encodeName( soundFile ).data();
|
|
|
|
d->externalPlayerEventId = eventId;
|
|
|
|
proc->start(TDEProcess::NotifyOnExit);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
soundFinished( eventId, Unknown );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::notifyByMessagebox(const TQString &text, int level, WId winId)
|
|
|
|
{
|
|
|
|
// ignore empty messages
|
|
|
|
if ( text.isEmpty() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// display message box for specified event level
|
|
|
|
switch( level ) {
|
|
|
|
default:
|
|
|
|
case KNotifyClient::Notification:
|
|
|
|
KMessageBox::informationWId( winId, text, i18n("Notification"), 0, false );
|
|
|
|
break;
|
|
|
|
case KNotifyClient::Warning:
|
|
|
|
KMessageBox::sorryWId( winId, text, i18n("Warning"), false );
|
|
|
|
break;
|
|
|
|
case KNotifyClient::Error:
|
|
|
|
KMessageBox::errorWId( winId, text, i18n("Error"), false );
|
|
|
|
break;
|
|
|
|
case KNotifyClient::Catastrophe:
|
|
|
|
KMessageBox::errorWId( winId, text, i18n("Catastrophe!"), false );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::notifyByPassivePopup( const TQString &text,
|
|
|
|
const TQString &appName,
|
|
|
|
TDEConfig* eventsFile,
|
|
|
|
WId senderWinId )
|
|
|
|
{
|
|
|
|
TDEIconLoader iconLoader( appName );
|
|
|
|
if ( eventsFile != NULL ) {
|
|
|
|
TDEConfigGroup config( eventsFile, "!Global!" );
|
|
|
|
TQString iconName = config.readEntry( "IconName", appName );
|
|
|
|
TQPixmap icon = iconLoader.loadIcon( iconName, TDEIcon::Small );
|
|
|
|
TQString title = config.readEntry( "Comment", appName );
|
|
|
|
KPassivePopup::message(title, text, icon, senderWinId);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
kdError() << "No events for app " << appName << "defined!" <<endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::notifyByExecute(const TQString &command, const TQString& event,
|
|
|
|
const TQString& fromApp, const TQString& text,
|
|
|
|
int winId, int eventId) {
|
|
|
|
if (!command.isEmpty()) {
|
|
|
|
// kdDebug() << "executing command '" << command << "'" << endl;
|
|
|
|
TQMap<TQChar,TQString> subst;
|
|
|
|
subst.insert( 'e', event );
|
|
|
|
subst.insert( 'a', fromApp );
|
|
|
|
subst.insert( 's', text );
|
|
|
|
subst.insert( 'w', TQString::number( winId ));
|
|
|
|
subst.insert( 'i', TQString::number( eventId ));
|
|
|
|
TQString execLine = KMacroExpander::expandMacrosShellQuote( command, subst );
|
|
|
|
if ( execLine.isEmpty() ) {
|
|
|
|
execLine = command; // fallback
|
|
|
|
}
|
|
|
|
|
|
|
|
TDEProcess p;
|
|
|
|
p.setUseShell(true);
|
|
|
|
p << execLine;
|
|
|
|
p.start(TDEProcess::DontCare);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KNotify::notifyByLogfile(const TQString &text, const TQString &file)
|
|
|
|
{
|
|
|
|
// ignore empty messages
|
|
|
|
if ( text.isEmpty() ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// open file in append mode
|
|
|
|
TQFile logFile(file);
|
|
|
|
if ( !logFile.open(IO_WriteOnly | IO_Append) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// append msg
|
|
|
|
TQTextStream strm( &logFile );
|
|
|
|
strm << "- KNotify " << TQDateTime::currentDateTime().toString() << ": ";
|
|
|
|
strm << text << endl;
|
|
|
|
|
|
|
|
// close file
|
|
|
|
logFile.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::notifyByStderr(const TQString &text)
|
|
|
|
{
|
|
|
|
// ignore empty messages
|
|
|
|
if ( text.isEmpty() ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// open stderr for output
|
|
|
|
TQTextStream strm( stderr, IO_WriteOnly );
|
|
|
|
|
|
|
|
// output msg
|
|
|
|
strm << "KNotify " << TQDateTime::currentDateTime().toString() << ": ";
|
|
|
|
strm << text << endl;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::notifyByTaskbar( WId win )
|
|
|
|
{
|
|
|
|
if( win == 0 ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
KWin::demandAttention( win );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::isGlobal(const TQString &eventname)
|
|
|
|
{
|
|
|
|
return d->globalEvents->hasGroup( eventname );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::setVolume( int volume )
|
|
|
|
{
|
|
|
|
if ( volume<0 ) volume=0;
|
|
|
|
if ( volume>=100 ) volume=100;
|
|
|
|
d->volume = volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::playTimeout()
|
|
|
|
{
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it;) {
|
|
|
|
TQPtrListIterator< KDE::PlayObject > current = it;
|
|
|
|
++it;
|
|
|
|
if ( (*current)->state() != Arts::posPlaying ) {
|
|
|
|
TQMap<KDE::PlayObject*,int>::Iterator eit = d->playObjectEventMap.find( *current );
|
|
|
|
if ( eit != d->playObjectEventMap.end() ) {
|
|
|
|
soundFinished( *eit, PlayedOK );
|
|
|
|
d->playObjectEventMap.remove( eit );
|
|
|
|
}
|
|
|
|
d->playObjects.remove( current );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !d->playObjects.count() ) {
|
|
|
|
d->playTimer->stop();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KNotify::isPlaying( const TQString& soundFile ) const
|
|
|
|
{
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it; ++it) {
|
|
|
|
if ( (*it)->mediaName() == soundFile ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::slotPlayerProcessExited( TDEProcess *proc )
|
|
|
|
{
|
|
|
|
soundFinished( d->externalPlayerEventId, (proc->normalExit() && proc->exitStatus() == 0) ? PlayedOK : Unknown );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::abortFirstPlayObject()
|
|
|
|
{
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
TQMap<KDE::PlayObject*,int>::Iterator it = d->playObjectEventMap.find( d->playObjects.getFirst() );
|
|
|
|
if ( it != d->playObjectEventMap.end() ) {
|
|
|
|
soundFinished( it.data(), Aborted );
|
|
|
|
d->playObjectEventMap.remove( it );
|
|
|
|
}
|
|
|
|
d->playObjects.removeFirst();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::soundFinished( int eventId, PlayingFinishedStatus reason )
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << eventId << (int) reason;
|
|
|
|
|
|
|
|
DCOPClient::mainClient()->emitDCOPSignal( "KNotify", "playingFinished(int,int)", data );
|
|
|
|
}
|
|
|
|
|
|
|
|
WId KNotify::checkWinId( const TQString &appName, WId senderWinId )
|
|
|
|
{
|
|
|
|
if ( senderWinId == 0 ) {
|
|
|
|
TQCString senderId = kapp->dcopClient()->senderId();
|
|
|
|
TQCString compare = (appName + "-mainwindow").latin1();
|
|
|
|
int len = compare.length();
|
|
|
|
// kdDebug() << "notifyByPassivePopup: appName=" << appName << " sender=" << senderId << endl;
|
|
|
|
|
|
|
|
QCStringList objs = kapp->dcopClient()->remoteObjects( senderId );
|
|
|
|
for (QCStringList::ConstIterator it = objs.begin(); it != objs.end(); ++it ) {
|
|
|
|
TQCString obj( *it );
|
|
|
|
if ( obj.left(len) == compare) {
|
|
|
|
// kdDebug( ) << "found " << obj << endl;
|
|
|
|
TQCString replyType;
|
|
|
|
TQByteArray data, replyData;
|
|
|
|
|
|
|
|
if ( kapp->dcopClient()->call(senderId, obj, "getWinID()", data, replyType, replyData) ) {
|
|
|
|
TQDataStream answer(replyData, IO_ReadOnly);
|
|
|
|
if (replyType == "int") {
|
|
|
|
answer >> senderWinId;
|
|
|
|
// kdDebug() << "SUCCESS, found getWinID(): type='" << TQString(replyType)
|
|
|
|
// << "' senderWinId=" << senderWinId << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return senderWinId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::restartedArtsd()
|
|
|
|
{
|
|
|
|
#ifndef WITHOUT_ARTS
|
|
|
|
delete d->audioManager;
|
|
|
|
d->audioManager = new KAudioManagerPlay( soundServer );
|
|
|
|
d->audioManager->setTitle( i18n( "Trinity System Notifications" ) );
|
|
|
|
d->audioManager->setAutoRestoreID( "KNotify Aman Play" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KNotify::sessionReady()
|
|
|
|
{
|
|
|
|
if( d->inStartup && !d->startupEvents.isEmpty()) {
|
|
|
|
kdDebug() << "There were knotify events while startup:" << d->startupEvents << endl;
|
|
|
|
}
|
|
|
|
d->inStartup = false;
|
|
|
|
}
|