26 #include <sys/types.h>
33 #include <dispatcher.h>
34 #include <flowsystem.h>
35 #include <qiomanager.h>
36 #include <soundserver.h>
41 #include <tqfileinfo.h>
42 #include <tqstringlist.h>
43 #include <tqtextstream.h>
46 #include <dcopclient.h>
47 #include <tdeaboutdata.h>
49 #include <kartsdispatcher.h>
50 #include <kartsserver.h>
52 #include <tdecmdlineargs.h>
53 #include <tdeconfig.h>
55 #include <tdeglobal.h>
57 #include <tdemessagebox.h>
58 #include <kpassivepopup.h>
59 #include <kiconloader.h>
60 #include <kmacroexpander.h>
62 #include <kplayobjectfactory.h>
63 #include <kaudiomanagerplay.h>
65 #include <tdeprocess.h>
66 #include <kstandarddirs.h>
67 #include <tdeuniqueapplication.h>
71 #include "knotify.moc"
78 TQMap<TQString, TDEConfig*> events;
79 TQMap<TQString, TDEConfig*> configs;
80 TQString externalPlayer;
84 TQPtrList<KDE::PlayObject> playObjects;
85 TQMap<KDE::PlayObject*,int> playObjectEventMap;
88 int externalPlayerEventId;
95 TQString startupEvents;
105 TDE_EXPORT
int kdemain(
int argc,
char **argv) {
107 "3.0",
I18N_NOOP(
"TDE Notification Server"),
108 TDEAboutData::License_GPL,
"(C) 1997-2003, KDE Developers");
109 aboutdata.addAuthor(
"Carsten Pfeiffer",
I18N_NOOP(
"Current Maintainer"),
"pfeiffer@kde.org");
110 aboutdata.addAuthor(
"Christian Esken",0,
"esken@kde.org");
111 aboutdata.addAuthor(
"Stefan Westerfeld",
I18N_NOOP(
"Sound support"),
"stefan@space.twc.de");
112 aboutdata.addAuthor(
"Charles Samuels",
I18N_NOOP(
"Previous Maintainer"),
"charles@kde.org");
138 artsKCMConfig.setGroup(
"Arts" );
139 bool useArts = artsKCMConfig.readBoolEntry(
"StartServer",
true );
141 useArts = config.readBoolEntry(
"Use Arts", useArts );
143 bool ok = config.readBoolEntry(
"Arts Init",
true );
145 if ( useArts && !ok ) {
148 i18n(
"During the previous startup, KNotify crashed while creating "
149 "Arts::Dispatcher. Do you want to try again or disable "
150 "aRts sound output?\n\n"
151 "If you choose to disable aRts output now, you can re-enable "
152 "it later or select an alternate sound player "
153 "in the System Notifications control panel."),
154 i18n(
"KNotify Problem"),
156 i18n(
"D&isable aRts Output"),
157 "KNotifyStartProgress",
160 == KMessageBox::No ) {
166 config.writeEntry(
"Arts Init",
false );
167 config.writeEntry(
"Use Arts", useArts );
177 config.writeEntry(
"Arts Init", useArts );
180 ok = config.readBoolEntry(
"KNotify Init",
true );
181 if ( useArts && !ok ) {
184 i18n(
"During the previous startup, KNotify crashed while instantiating "
185 "KNotify. Do you want to try again or disable "
186 "aRts sound output?\n\n"
187 "If you choose to disable aRts output now, you can re-enable "
188 "it later or select an alternate sound player "
189 "in the System Notifications control panel."),
190 i18n(
"KNotify Problem"),
192 i18n(
"D&isable aRts Output"),
193 "KNotifyStartProgress",
196 == KMessageBox::No ) {
206 config.writeEntry(
"KNotify Init",
false );
207 config.writeEntry(
"Use Arts", useArts );
211 KNotify *notify =
new KNotify( useArts );
213 config.writeEntry(
"KNotify Init",
true );
219 KNotify *notify =
new KNotify(
false );
223 app.
dcopClient()->setDefaultObject(
"Notify" );
227 int ret = app.exec();
237 KNotify::KNotify(
bool useArts )
238 : TQObject(), DCOPObject(
"Notify")
240 d =
new KNotifyPrivate;
241 d->globalEvents =
new TDEConfig(
"knotify/eventsrc",
true,
false,
"data");
242 d->globalConfig =
new TDEConfig(
"knotify.eventsrc",
true,
false);
243 d->externalPlayerProc = 0;
244 d->useArts = useArts;
247 d->playObjects.setAutoDelete(
true);
250 connect( soundServer, TQ_SIGNAL( restartedServer() ),
this, TQ_SLOT( restartedArtsd() ) );
265 d->playObjects.clear();
267 delete d->globalEvents;
268 delete d->globalConfig;
269 delete d->externalPlayerProc;
270 delete d->audioManager;
276 void KNotify::loadConfig() {
280 d->useExternal = kc->
readBoolEntry(
"Use external player",
false );
284 if ( d->externalPlayer.isEmpty() ) {
285 TQStringList players;
286 players <<
"wavplay" <<
"aplay" <<
"auplay";
287 TQStringList::Iterator it = players.begin();
288 while ( d->externalPlayer.isEmpty() && it != players.end() ) {
299 void KNotify::reconfigure()
301 kapp->config()->reparseConfiguration();
305 d->globalConfig->reparseConfiguration();
306 for ( TQMapIterator<TQString,TDEConfig*> it = d->configs.begin(); it != d->configs.end(); ++it ) {
313 void KNotify::notify(
const TQString &event,
const TQString &fromApp,
314 const TQString &text, TQString sound, TQString file,
315 int present,
int level)
317 notify( event, fromApp, text, sound, file, present, level, 0, 1 );
320 void KNotify::notify(
const TQString &event,
const TQString &fromApp,
321 const TQString &text, TQString sound, TQString file,
322 int present,
int level,
int winId)
324 notify( event, fromApp, text, sound, file, present, level, winId, 1 );
327 void KNotify::notify(
const TQString &event,
const TQString &fromApp,
328 const TQString &text, TQString sound, TQString file,
329 int present,
int level,
int winId,
int eventId )
334 d->startupEvents +=
"(" +
event +
":" + fromApp +
")";
337 TQString commandline;
342 if ( !
event.isEmpty() ) {
345 if ( d->events.contains( fromApp ) ) {
346 eventsFile = d->events[fromApp];
349 eventsFile=
new TDEConfig(
locate(
"data", fromApp+
"/eventsrc"),
true,
false);
350 d->events.insert( fromApp, eventsFile );
352 if ( d->configs.contains( fromApp) ) {
353 configFile = d->configs[fromApp];
356 configFile=
new TDEConfig(fromApp+
".eventsrc",
true,
false);
357 d->configs.insert( fromApp, configFile );
360 if ( !eventsFile->
hasGroup( event ) && isGlobal(event) ) {
361 eventsFile = d->globalEvents;
362 configFile = d->globalConfig;
370 present = configFile->
readNumEntry(
"presentation", -1 );
373 present = eventsFile->
readNumEntry(
"default_presentation", 0 );
377 if( present & KNotifyClient::Sound ) {
378 TQString theSound = configFile->
readPathEntry(
"soundfile" );
379 if ( theSound.isEmpty() ) {
382 if ( !theSound.isEmpty() ) {
388 if( present & KNotifyClient::Logfile ) {
390 if ( theFile.isEmpty() ) {
393 if ( !theFile.isEmpty() ) {
399 if( present & KNotifyClient::Messagebox ) {
406 if ( commandline.isEmpty() ) {
407 commandline = eventsFile->
readPathEntry(
"default_commandline" );
413 if ( present & KNotifyClient::Sound ) {
414 notifyBySound( sound, fromApp, eventId );
418 notifyByExecute( commandline, event, fromApp, text, winId, eventId );
421 if ( present & KNotifyClient::Logfile ) {
422 notifyByLogfile( text, file );
425 if ( present & KNotifyClient::Stderr ) {
426 notifyByStderr( text );
430 notifyByTaskbar( checkWinId( fromApp, winId ));
434 notifyByPassivePopup( text, fromApp, eventsFile, checkWinId( fromApp, winId ));
436 else if ( present & KNotifyClient::Messagebox ) {
437 notifyByMessagebox( text, level, checkWinId( fromApp, winId ));
441 TQDataStream ds(qbd, IO_WriteOnly);
442 ds <<
event << fromApp << text << sound << file << present << level << winId << eventId;
443 emitDCOPSignal(
"notifySignal(TQString,TQString,TQString,TQString,TQString,int,int,int,int)", qbd);
447 bool KNotify::notifyBySound(
const TQString &sound,
const TQString &appname,
int eventId )
449 if (sound.isEmpty()) {
450 soundFinished( eventId, NoSoundFile );
454 bool external = d->useExternal && !d->externalPlayer.isEmpty();
456 TQString soundFile(sound);
457 if ( TQFileInfo(sound).isRelative() ) {
458 TQString search = TQString(
"%1/sounds/%2").arg(appname).arg(sound);
460 if ( soundFile.isEmpty() ) {
461 soundFile =
locate(
"sound", sound );
464 if ( soundFile.isEmpty() || isPlaying( soundFile ) ) {
465 soundFinished( eventId, soundFile.isEmpty() ? NoSoundFile : FileAlreadyPlaying );
477 soundFinished( eventId, NoSoundSupport );
483 while( d->playObjects.count()>5 ) {
484 abortFirstPlayObject();
488 if( d->audioManager ) {
489 factory.setAudioManagerPlay( d->audioManager );
493 KDE::PlayObject *playObject = factory.createPlayObject(soundURL,
false);
495 if (playObject->
isNull()) {
496 soundFinished( eventId, NoSoundSupport );
501 if ( d->volume != 100 ) {
504 Arts::StereoVolumeControl volumeControl = Arts::DynamicCast(soundServer->
server().createObject(
"Arts::StereoVolumeControl"));
505 Arts::PlayObject player = playObject->
object();
506 Arts::Synth_AMAN_PLAY ap = d->audioManager->amanPlay();
507 if( ! volumeControl.isNull() && ! player.isNull() && ! ap.isNull() ) {
508 volumeControl.scaleFactor( d->volume/100.0 );
511 Arts::disconnect( player,
"left", ap,
"left" );
512 Arts::disconnect( player,
"right", ap,
"right" );
515 volumeControl.start();
517 Arts::connect(player,
"left",volumeControl,
"inleft");
518 Arts::connect(player,
"right",volumeControl,
"inright");
520 Arts::connect(volumeControl,
"outleft",ap,
"left");
521 Arts::connect(volumeControl,
"outright",ap,
"right");
523 player._addChild( volumeControl,
"volume" );
528 d->playObjects.append( playObject );
529 d->playObjectEventMap.insert( playObject, eventId );
531 if ( !d->playTimer ) {
532 d->playTimer =
new TQTimer(
this );
533 connect( d->playTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( playTimeout() ) );
535 if ( !d->playTimer->isActive() ) {
536 d->playTimer->start( 1000 );
541 else if(!d->externalPlayer.isEmpty()) {
545 proc = d->externalPlayerProc =
new TDEProcess;
546 connect( proc, TQ_SIGNAL( processExited(
TDEProcess * )), TQ_SLOT( slotPlayerProcessExited(
TDEProcess * )));
549 soundFinished( eventId, PlayerBusy );
553 (*proc) << d->externalPlayer << TQFile::encodeName( soundFile ).data();
554 d->externalPlayerEventId = eventId;
559 soundFinished( eventId, Unknown );
563 bool KNotify::notifyByMessagebox(
const TQString &text,
int level, WId winId)
566 if ( text.isEmpty() ) {
573 case KNotifyClient::Notification:
576 case KNotifyClient::Warning:
579 case KNotifyClient::Error:
582 case KNotifyClient::Catastrophe:
590 bool KNotify::notifyByPassivePopup(
const TQString &text,
591 const TQString &appName,
596 if ( eventsFile != NULL ) {
598 TQString iconName = config.readEntry(
"IconName", appName );
600 TQString title = config.readEntry(
"Comment", appName );
604 kdError() <<
"No events for app " << appName <<
"defined!" <<
endl;
610 bool KNotify::notifyByExecute(
const TQString &command,
const TQString& event,
611 const TQString& fromApp,
const TQString& text,
612 int winId,
int eventId) {
613 if (!command.isEmpty()) {
615 TQMap<TQChar,TQString> subst;
616 subst.insert(
'e', event );
617 subst.insert(
'a', fromApp );
618 subst.insert(
's', text );
619 subst.insert(
'w', TQString::number( winId ));
620 subst.insert(
'i', TQString::number( eventId ));
622 if ( execLine.isEmpty() ) {
636 bool KNotify::notifyByLogfile(
const TQString &text,
const TQString &file)
639 if ( text.isEmpty() ) {
644 TQFile logFile(file);
645 if ( !logFile.open(IO_WriteOnly | IO_Append) ) {
650 TQTextStream strm( &logFile );
651 strm <<
"- KNotify " << TQDateTime::currentDateTime().toString() <<
": ";
652 strm << text <<
endl;
659 bool KNotify::notifyByStderr(
const TQString &text)
662 if ( text.isEmpty() ) {
667 TQTextStream strm( stderr, IO_WriteOnly );
670 strm <<
"KNotify " << TQDateTime::currentDateTime().toString() <<
": ";
671 strm << text <<
endl;
676 bool KNotify::notifyByTaskbar( WId win )
685 bool KNotify::isGlobal(
const TQString &eventname)
687 return d->globalEvents->hasGroup( eventname );
690 void KNotify::setVolume(
int volume )
692 if ( volume<0 ) volume=0;
693 if ( volume>=100 ) volume=100;
697 void KNotify::playTimeout()
700 for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it;) {
701 TQPtrListIterator< KDE::PlayObject > current = it;
703 if ( (*current)->state() != Arts::posPlaying ) {
704 TQMap<KDE::PlayObject*,int>::Iterator eit = d->playObjectEventMap.find( *current );
705 if ( eit != d->playObjectEventMap.end() ) {
706 soundFinished( *eit, PlayedOK );
707 d->playObjectEventMap.remove( eit );
709 d->playObjects.remove( current );
712 if ( !d->playObjects.count() ) {
713 d->playTimer->stop();
718 bool KNotify::isPlaying(
const TQString& soundFile )
const
721 for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it; ++it) {
722 if ( (*it)->mediaName() == soundFile ) {
730 void KNotify::slotPlayerProcessExited(
TDEProcess *proc )
732 soundFinished( d->externalPlayerEventId, (proc->
normalExit() && proc->
exitStatus() == 0) ? PlayedOK : Unknown );
735 void KNotify::abortFirstPlayObject()
738 TQMap<KDE::PlayObject*,int>::Iterator it = d->playObjectEventMap.find( d->playObjects.getFirst() );
739 if ( it != d->playObjectEventMap.end() ) {
740 soundFinished( it.data(), Aborted );
741 d->playObjectEventMap.remove( it );
743 d->playObjects.removeFirst();
747 void KNotify::soundFinished(
int eventId, PlayingFinishedStatus reason )
750 TQDataStream stream( data, IO_WriteOnly );
751 stream << eventId << (int) reason;
753 DCOPClient::mainClient()->emitDCOPSignal(
"KNotify",
"playingFinished(int,int)", data );
756 WId KNotify::checkWinId(
const TQString &appName, WId senderWinId )
758 if ( senderWinId == 0 ) {
759 TQCString senderId = kapp->dcopClient()->senderId();
760 TQCString compare = (appName +
"-mainwindow").latin1();
761 int len = compare.length();
764 QCStringList objs = kapp->dcopClient()->remoteObjects( senderId );
765 for (QCStringList::ConstIterator it = objs.begin(); it != objs.end(); ++it ) {
766 TQCString obj( *it );
767 if ( obj.left(len) == compare) {
770 TQByteArray data, replyData;
772 if ( kapp->dcopClient()->call(senderId, obj,
"getWinID()", data, replyType, replyData) ) {
773 TQDataStream answer(replyData, IO_ReadOnly);
774 if (replyType ==
"int") {
775 answer >> senderWinId;
786 void KNotify::restartedArtsd()
789 delete d->audioManager;
791 d->audioManager->setTitle( i18n(
"Trinity System Notifications" ) );
792 d->audioManager->setAutoRestoreID(
"KNotify Aman Play" );
796 void KNotify::sessionReady()
798 if( d->inStartup && !d->startupEvents.isEmpty()) {
799 kdDebug() <<
"There were knotify events while startup:" << d->startupEvents <<
endl;
801 d->inStartup =
false;
KArtsDispatcher ensures that an instance of Arts::Dispatcher using an Arts::QIOManager exists.
KArtsServer is a wrapper to conveniently get a reference to a SoundServer, and restart artsd when nec...
Arts::SoundServerV2 server(void)
Get a verified reference to the SoundServerV2, (re)starting artsd using the kcontrol-specified settin...
KDE Wrapper for Arts::Synth_AMAN_PLAY.
This class implements a factory to create KDE::PlayObjects for a given URL and mimetype.
This class acts as a general interface to the KDE multimedia framework.
bool isNull()
return true if this != 0.
Arts::PlayObject object()
Returns the internal Arts::PlayObject.
void play()
causes the PlayObject to start the play back.
static int questionYesNo(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const KGuiItem &buttonYes=KStdGuiItem::yes(), const KGuiItem &buttonNo=KStdGuiItem::no(), const TQString &dontAskAgainName=TQString::null, int options=Notify)
static void sorryWId(WId parent_id, const TQString &text, const TQString &caption=TQString::null, int options=Notify)
static void informationWId(WId parent_id, const TQString &text, const TQString &caption=TQString::null, const TQString &dontShowAgainName=TQString::null, int options=Notify)
static void errorWId(WId parent_id, const TQString &text, const TQString &caption=TQString::null, int options=Notify)
void setPath(const TQString &path)
static void demandAttention(WId win, bool set=true)
void disableSessionManagement()
static DCOPClient * dcopClient()
static void init(int _argc, char **_argv, const char *_appname, const char *programName, const char *_description, const char *_version, bool noKApp=false)
int readNumEntry(const TQString &pKey, int nDefault=0) const
bool readBoolEntry(const TQString &pKey, bool bDefault=false) const
bool hasGroup(const TQString &group) const
TQString readPathEntry(const TQString &pKey, const TQString &aDefault=TQString::null) const
void setGroup(const TQString &group)
static TDEConfig * config()
static TDEInstance * instance()
TDEStandardDirs * dirs() const
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
void setUseShell(bool useShell, const char *shell=0)
static TQString findExe(const TQString &appname, const TQString &pathstr=TQString::null, bool ignoreExecBit=false)
TQString findResource(const char *type, const TQString &filename) const
static void addCmdLineOptions()
kndbgstream & endl(kndbgstream &s)
kdbgstream kdError(int area=0)
kdbgstream kdDebug(int area=0)
TQString locate(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())
TQString expandMacrosShellQuote(const TQString &str, const TQMap< TQChar, TQString > &map, TQChar c='%')
int event(const TQString &message, const TQString &text=TQString::null) TDE_DEPRECATED