knotify.cpp
00001 /* 00002 Copyright (c) 1997 Christian Esken (esken@kde.org) 00003 2000 Charles Samuels (charles@kde.org) 00004 2000 Stefan Schimanski (1Stein@gmx.de) 00005 2000 Matthias Ettrich (ettrich@kde.org) 00006 2000 Waldo Bastian <bastian@kde.org> 00007 2000-2003 Carsten Pfeiffer <pfeiffer@kde.org> 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2, or (at your option) 00012 any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00022 */ 00023 00024 // C headers 00025 #include <fcntl.h> 00026 #include <sys/types.h> 00027 #include <sys/stat.h> 00028 00029 #include <config.h> 00030 #ifndef WITHOUT_ARTS 00031 // aRts headers 00032 #include <connect.h> 00033 #include <dispatcher.h> 00034 #include <flowsystem.h> 00035 #include <qiomanager.h> 00036 #include <soundserver.h> 00037 #endif 00038 00039 // QT headers 00040 #include <tqfile.h> 00041 #include <tqfileinfo.h> 00042 #include <tqstringlist.h> 00043 #include <tqtextstream.h> 00044 00045 // KDE headers 00046 #include <dcopclient.h> 00047 #include <tdeaboutdata.h> 00048 #ifndef WITHOUT_ARTS 00049 #include <kartsdispatcher.h> 00050 #include <kartsserver.h> 00051 #endif 00052 #include <tdecmdlineargs.h> 00053 #include <tdeconfig.h> 00054 #include <kdebug.h> 00055 #include <tdeglobal.h> 00056 #include <tdelocale.h> 00057 #include <tdemessagebox.h> 00058 #include <kpassivepopup.h> 00059 #include <kiconloader.h> 00060 #include <kmacroexpander.h> 00061 #ifndef WITHOUT_ARTS 00062 #include <kplayobjectfactory.h> 00063 #include <kaudiomanagerplay.h> 00064 #endif 00065 #include <kprocess.h> 00066 #include <kstandarddirs.h> 00067 #include <kuniqueapplication.h> 00068 #include <twin.h> 00069 00070 #include "knotify.h" 00071 #include "knotify.moc" 00072 00073 class KNotifyPrivate 00074 { 00075 public: 00076 TDEConfig* globalEvents; 00077 TDEConfig* globalConfig; 00078 TQMap<TQString, TDEConfig*> events; 00079 TQMap<TQString, TDEConfig*> configs; 00080 TQString externalPlayer; 00081 TDEProcess *externalPlayerProc; 00082 00083 #ifndef WITHOUT_ARTS 00084 TQPtrList<KDE::PlayObject> playObjects; 00085 TQMap<KDE::PlayObject*,int> playObjectEventMap; 00086 KAudioManagerPlay *audioManager; 00087 #endif 00088 int externalPlayerEventId; 00089 00090 bool useExternal; 00091 bool useArts; 00092 int volume; 00093 TQTimer *playTimer; 00094 bool inStartup; 00095 TQString startupEvents; 00096 }; 00097 00098 // Yes, it's ugly to put this here, but this facilitates the cautious startup 00099 // procedure. 00100 #ifndef WITHOUT_ARTS 00101 KArtsServer *soundServer = 0; 00102 #endif 00103 00104 extern "C"{ 00105 KDE_EXPORT int kdemain(int argc, char **argv) { 00106 TDEAboutData aboutdata("knotify", I18N_NOOP("KNotify"), 00107 "3.0", I18N_NOOP("TDE Notification Server"), 00108 TDEAboutData::License_GPL, "(C) 1997-2003, KDE Developers"); 00109 aboutdata.addAuthor("Carsten Pfeiffer",I18N_NOOP("Current Maintainer"),"pfeiffer@kde.org"); 00110 aboutdata.addAuthor("Christian Esken",0,"esken@kde.org"); 00111 aboutdata.addAuthor("Stefan Westerfeld",I18N_NOOP("Sound support"),"stefan@space.twc.de"); 00112 aboutdata.addAuthor("Charles Samuels",I18N_NOOP("Previous Maintainer"),"charles@kde.org"); 00113 00114 TDECmdLineArgs::init( argc, argv, &aboutdata ); 00115 KUniqueApplication::addCmdLineOptions(); 00116 00117 // initialize application 00118 if ( !KUniqueApplication::start() ) { 00119 kdDebug() << "Running knotify found" << endl; 00120 return 0; 00121 } 00122 00123 KUniqueApplication app; 00124 app.disableSessionManagement(); 00125 00126 // KNotify is started on KDE startup and on demand (using 00127 // KNotifClient::startDaemon()) whenever a KNotify event occurs. Especially 00128 // KWin may fire many events (e.g. when a window pops up). When we have 00129 // problems with aRts or the installation, we might get an infinite loop 00130 // of knotify crashing, popping up the crashhandler window and twin firing 00131 // another event, starting knotify again... 00132 // We try to prevent this by tracking our startup and offer options to 00133 // abort this. 00134 00135 #ifndef WITHOUT_ARTS 00136 TDEConfigGroup config( TDEGlobal::config(), "StartProgress" ); 00137 TDEConfig artsKCMConfig( "kcmartsrc" ); 00138 artsKCMConfig.setGroup( "Arts" ); 00139 bool useArts = artsKCMConfig.readBoolEntry( "StartServer", true ); 00140 if (useArts) { 00141 useArts = config.readBoolEntry( "Use Arts", useArts ); 00142 } 00143 bool ok = config.readBoolEntry( "Arts Init", true ); 00144 00145 if ( useArts && !ok ) { 00146 if ( KMessageBox::questionYesNo( 00147 0L, 00148 i18n("During the previous startup, KNotify crashed while creating " 00149 "Arts::Dispatcher. Do you want to try again or disable " 00150 "aRts sound output?\n\n" 00151 "If you choose to disable aRts output now, you can re-enable " 00152 "it later or select an alternate sound player " 00153 "in the System Notifications control panel."), 00154 i18n("KNotify Problem"), 00155 i18n("&Try Again"), 00156 i18n("D&isable aRts Output"), 00157 "KNotifyStartProgress", 00158 0 /* don't call KNotify :) */ 00159 ) 00160 == KMessageBox::No ) { 00161 useArts = false; 00162 } 00163 } 00164 00165 // when ArtsDispatcher crashes, we know it the next start. 00166 config.writeEntry( "Arts Init", false ); 00167 config.writeEntry( "Use Arts", useArts ); 00168 config.sync(); 00169 00170 KArtsDispatcher *dispatcher = 0; 00171 if ( useArts ) { 00172 dispatcher = new KArtsDispatcher; 00173 soundServer = new KArtsServer; 00174 } 00175 00176 // ok, seemed to work. 00177 config.writeEntry("Arts Init", useArts ); 00178 config.sync(); 00179 00180 ok = config.readBoolEntry( "KNotify Init", true ); 00181 if ( useArts && !ok ) { 00182 if ( KMessageBox::questionYesNo( 00183 0L, 00184 i18n("During the previous startup, KNotify crashed while instantiating " 00185 "KNotify. Do you want to try again or disable " 00186 "aRts sound output?\n\n" 00187 "If you choose to disable aRts output now, you can re-enable " 00188 "it later or select an alternate sound player " 00189 "in the System Notifications control panel."), 00190 i18n("KNotify Problem"), 00191 i18n("&Try Again"), 00192 i18n("D&isable aRts Output"), 00193 "KNotifyStartProgress", 00194 0 /* don't call KNotify :) */ 00195 ) 00196 == KMessageBox::No ) { 00197 useArts = false; 00198 delete soundServer; 00199 soundServer = 0L; 00200 delete dispatcher; 00201 dispatcher = 0L; 00202 } 00203 } 00204 00205 // when KNotify instantiation crashes, we know it the next start. 00206 config.writeEntry( "KNotify Init", false ); 00207 config.writeEntry( "Use Arts", useArts ); 00208 config.sync(); 00209 00210 // start notify service 00211 KNotify *notify = new KNotify( useArts ); 00212 00213 config.writeEntry( "KNotify Init", true ); 00214 config.sync(); 00215 00216 #else 00217 00218 // start notify service, without aRts 00219 KNotify *notify = new KNotify( false ); 00220 00221 #endif 00222 00223 app.dcopClient()->setDefaultObject( "Notify" ); 00224 app.dcopClient()->setDaemonMode( true ); 00225 // kdDebug() << "knotify starting" << endl; 00226 00227 int ret = app.exec(); 00228 delete notify; 00229 #ifndef WITHOUT_ARTS 00230 delete soundServer; 00231 delete dispatcher; 00232 #endif 00233 return ret; 00234 } 00235 } // end extern "C" 00236 00237 KNotify::KNotify( bool useArts ) 00238 : TQObject(), DCOPObject("Notify") 00239 { 00240 d = new KNotifyPrivate; 00241 d->globalEvents = new TDEConfig("knotify/eventsrc", true, false, "data"); 00242 d->globalConfig = new TDEConfig("knotify.eventsrc", true, false); 00243 d->externalPlayerProc = 0; 00244 d->useArts = useArts; 00245 d->inStartup = true; 00246 #ifndef WITHOUT_ARTS 00247 d->playObjects.setAutoDelete(true); 00248 d->audioManager = 0; 00249 if( useArts ) { 00250 connect( soundServer, TQT_SIGNAL( restartedServer() ), this, TQT_SLOT( restartedArtsd() ) ); 00251 restartedArtsd(); //started allready need to initialize d->audioManager 00252 } 00253 #endif 00254 d->volume = 100; 00255 d->playTimer = 0; 00256 00257 loadConfig(); 00258 } 00259 00260 KNotify::~KNotify() 00261 { 00262 reconfigure(); 00263 00264 #ifndef WITHOUT_ARTS 00265 d->playObjects.clear(); 00266 00267 delete d->globalEvents; 00268 delete d->globalConfig; 00269 delete d->externalPlayerProc; 00270 delete d->audioManager; 00271 #endif 00272 delete d; 00273 } 00274 00275 00276 void KNotify::loadConfig() { 00277 // load external player settings 00278 TDEConfig *kc = TDEGlobal::config(); 00279 kc->setGroup("Misc"); 00280 d->useExternal = kc->readBoolEntry( "Use external player", false ); 00281 d->externalPlayer = kc->readPathEntry("External player"); 00282 00283 // try to locate a suitable player if none is configured 00284 if ( d->externalPlayer.isEmpty() ) { 00285 TQStringList players; 00286 players << "wavplay" << "aplay" << "auplay"; 00287 TQStringList::Iterator it = players.begin(); 00288 while ( d->externalPlayer.isEmpty() && it != players.end() ) { 00289 d->externalPlayer = TDEStandardDirs::findExe( *it ); 00290 ++it; 00291 } 00292 } 00293 00294 // load default volume 00295 d->volume = kc->readNumEntry( "Volume", 100 ); 00296 } 00297 00298 00299 void KNotify::reconfigure() 00300 { 00301 kapp->config()->reparseConfiguration(); 00302 loadConfig(); 00303 00304 // clear loaded config files 00305 d->globalConfig->reparseConfiguration(); 00306 for ( TQMapIterator<TQString,TDEConfig*> it = d->configs.begin(); it != d->configs.end(); ++it ) { 00307 delete it.data(); 00308 } 00309 d->configs.clear(); 00310 } 00311 00312 00313 void KNotify::notify(const TQString &event, const TQString &fromApp, 00314 const TQString &text, TQString sound, TQString file, 00315 int present, int level) 00316 { 00317 notify( event, fromApp, text, sound, file, present, level, 0, 1 ); 00318 } 00319 00320 void KNotify::notify(const TQString &event, const TQString &fromApp, 00321 const TQString &text, TQString sound, TQString file, 00322 int present, int level, int winId) 00323 { 00324 notify( event, fromApp, text, sound, file, present, level, winId, 1 ); 00325 } 00326 00327 void KNotify::notify(const TQString &event, const TQString &fromApp, 00328 const TQString &text, TQString sound, TQString file, 00329 int present, int level, int winId, int eventId ) 00330 { 00331 // kdDebug() << "event=" << event << " fromApp=" << fromApp << " text=" << text << " sound=" << sound << 00332 // " file=" << file << " present=" << present << " level=" << level << " winId=" << winId << " eventId=" << eventId << endl; 00333 if( d->inStartup ) { 00334 d->startupEvents += "(" + event + ":" + fromApp + ")"; 00335 } 00336 00337 TQString commandline; 00338 TDEConfig *eventsFile = NULL; 00339 TDEConfig *configFile = NULL; 00340 00341 // check for valid events 00342 if ( !event.isEmpty() ) { 00343 00344 // get config file 00345 if ( d->events.contains( fromApp ) ) { 00346 eventsFile = d->events[fromApp]; 00347 } 00348 else { 00349 eventsFile=new TDEConfig(locate("data", fromApp+"/eventsrc"),true,false); 00350 d->events.insert( fromApp, eventsFile ); 00351 } 00352 if ( d->configs.contains( fromApp) ) { 00353 configFile = d->configs[fromApp]; 00354 } 00355 else { 00356 configFile=new TDEConfig(fromApp+".eventsrc",true,false); 00357 d->configs.insert( fromApp, configFile ); 00358 } 00359 00360 if ( !eventsFile->hasGroup( event ) && isGlobal(event) ) { 00361 eventsFile = d->globalEvents; 00362 configFile = d->globalConfig; 00363 } 00364 00365 eventsFile->setGroup( event ); 00366 configFile->setGroup( event ); 00367 00368 // get event presentation 00369 if ( present==-1 ) { 00370 present = configFile->readNumEntry( "presentation", -1 ); 00371 } 00372 if ( present==-1 ) { 00373 present = eventsFile->readNumEntry( "default_presentation", 0 ); 00374 } 00375 00376 // get sound file name 00377 if( present & KNotifyClient::Sound ) { 00378 TQString theSound = configFile->readPathEntry( "soundfile" ); 00379 if ( theSound.isEmpty() ) { 00380 theSound = eventsFile->readPathEntry( "default_sound" ); 00381 } 00382 if ( !theSound.isEmpty() ) { 00383 sound = theSound; 00384 } 00385 } 00386 00387 // get log file name 00388 if( present & KNotifyClient::Logfile ) { 00389 TQString theFile = configFile->readPathEntry( "logfile" ); 00390 if ( theFile.isEmpty() ) { 00391 theFile = eventsFile->readPathEntry( "default_logfile" ); 00392 } 00393 if ( !theFile.isEmpty() ) { 00394 file = theFile; 00395 } 00396 } 00397 00398 // get default event level 00399 if( present & KNotifyClient::Messagebox ) { 00400 level = eventsFile->readNumEntry( "level", 0 ); 00401 } 00402 00403 // get command line 00404 if (present & KNotifyClient::Execute ) { 00405 commandline = configFile->readPathEntry( "commandline" ); 00406 if ( commandline.isEmpty() ) { 00407 commandline = eventsFile->readPathEntry( "default_commandline" ); 00408 } 00409 } 00410 } 00411 00412 // emit event 00413 if ( present & KNotifyClient::Sound ) { // && TQFile(sound).isReadable() 00414 notifyBySound( sound, fromApp, eventId ); 00415 } 00416 00417 if ( present & KNotifyClient::Execute ) { 00418 notifyByExecute( commandline, event, fromApp, text, winId, eventId ); 00419 } 00420 00421 if ( present & KNotifyClient::Logfile ) { // && TQFile(file).isWritable() 00422 notifyByLogfile( text, file ); 00423 } 00424 00425 if ( present & KNotifyClient::Stderr ) { 00426 notifyByStderr( text ); 00427 } 00428 00429 if ( present & KNotifyClient::Taskbar ) { 00430 notifyByTaskbar( checkWinId( fromApp, winId )); 00431 } 00432 00433 if ( present & KNotifyClient::PassivePopup ) { 00434 notifyByPassivePopup( text, fromApp, eventsFile, checkWinId( fromApp, winId )); 00435 } 00436 else if ( present & KNotifyClient::Messagebox ) { 00437 notifyByMessagebox( text, level, checkWinId( fromApp, winId )); 00438 } 00439 00440 TQByteArray qbd; 00441 TQDataStream ds(qbd, IO_WriteOnly); 00442 ds << event << fromApp << text << sound << file << present << level << winId << eventId; 00443 emitDCOPSignal("notifySignal(TQString,TQString,TQString,TQString,TQString,int,int,int,int)", qbd); 00444 } 00445 00446 00447 bool KNotify::notifyBySound( const TQString &sound, const TQString &appname, int eventId ) 00448 { 00449 if (sound.isEmpty()) { 00450 soundFinished( eventId, NoSoundFile ); 00451 return false; 00452 } 00453 00454 bool external = d->useExternal && !d->externalPlayer.isEmpty(); 00455 // get file name 00456 TQString soundFile(sound); 00457 if ( TQFileInfo(sound).isRelative() ) { 00458 TQString search = TQString("%1/sounds/%2").arg(appname).arg(sound); 00459 soundFile = TDEGlobal::instance()->dirs()->findResource("data", search); 00460 if ( soundFile.isEmpty() ) { 00461 soundFile = locate( "sound", sound ); 00462 } 00463 } 00464 if ( soundFile.isEmpty() || isPlaying( soundFile ) ) { 00465 soundFinished( eventId, soundFile.isEmpty() ? NoSoundFile : FileAlreadyPlaying ); 00466 return false; 00467 } 00468 00469 00470 // kdDebug() << "KNotify::notifyBySound - trying to play file " << soundFile << endl; 00471 00472 if (!external) { 00473 //If we disabled using aRts, just return, 00474 //(If we don't, we'll blow up accessing the null soundServer) 00475 if (!d->useArts) 00476 { 00477 soundFinished( eventId, NoSoundSupport ); 00478 return false; 00479 } 00480 00481 #ifndef WITHOUT_ARTS 00482 // play sound finally 00483 while( d->playObjects.count()>5 ) { 00484 abortFirstPlayObject(); 00485 } 00486 00487 KDE::PlayObjectFactory factory(soundServer->server()); 00488 if( d->audioManager ) { 00489 factory.setAudioManagerPlay( d->audioManager ); 00490 } 00491 KURL soundURL; 00492 soundURL.setPath(soundFile); 00493 KDE::PlayObject *playObject = factory.createPlayObject(soundURL, false); 00494 00495 if (playObject->isNull()) { 00496 soundFinished( eventId, NoSoundSupport ); 00497 delete playObject; 00498 return false; 00499 } 00500 00501 if ( d->volume != 100 ) { 00502 // It works to access the playObject immediately because we don't allow 00503 // non-file URLs for sounds. 00504 Arts::StereoVolumeControl volumeControl = Arts::DynamicCast(soundServer->server().createObject("Arts::StereoVolumeControl")); 00505 Arts::PlayObject player = playObject->object(); 00506 Arts::Synth_AMAN_PLAY ap = d->audioManager->amanPlay(); 00507 if( ! volumeControl.isNull() && ! player.isNull() && ! ap.isNull() ) { 00508 volumeControl.scaleFactor( d->volume/100.0 ); 00509 00510 ap.stop(); 00511 Arts::disconnect( player, "left", ap, "left" ); 00512 Arts::disconnect( player, "right", ap, "right" ); 00513 00514 ap.start(); 00515 volumeControl.start(); 00516 00517 Arts::connect(player,"left",volumeControl,"inleft"); 00518 Arts::connect(player,"right",volumeControl,"inright"); 00519 00520 Arts::connect(volumeControl,"outleft",ap,"left"); 00521 Arts::connect(volumeControl,"outright",ap,"right"); 00522 00523 player._addChild( volumeControl, "volume" ); 00524 } 00525 } 00526 00527 playObject->play(); 00528 d->playObjects.append( playObject ); 00529 d->playObjectEventMap.insert( playObject, eventId ); 00530 00531 if ( !d->playTimer ) { 00532 d->playTimer = new TQTimer( this ); 00533 connect( d->playTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( playTimeout() ) ); 00534 } 00535 if ( !d->playTimer->isActive() ) { 00536 d->playTimer->start( 1000 ); 00537 } 00538 #endif 00539 return true; 00540 } 00541 else if(!d->externalPlayer.isEmpty()) { 00542 // use an external player to play the sound 00543 TDEProcess *proc = d->externalPlayerProc; 00544 if (!proc) { 00545 proc = d->externalPlayerProc = new TDEProcess; 00546 connect( proc, TQT_SIGNAL( processExited( TDEProcess * )), TQT_SLOT( slotPlayerProcessExited( TDEProcess * ))); 00547 } 00548 if (proc->isRunning()) { 00549 soundFinished( eventId, PlayerBusy ); 00550 return false; // Skip 00551 } 00552 proc->clearArguments(); 00553 (*proc) << d->externalPlayer << TQFile::encodeName( soundFile ).data(); 00554 d->externalPlayerEventId = eventId; 00555 proc->start(TDEProcess::NotifyOnExit); 00556 return true; 00557 } 00558 00559 soundFinished( eventId, Unknown ); 00560 return false; 00561 } 00562 00563 bool KNotify::notifyByMessagebox(const TQString &text, int level, WId winId) 00564 { 00565 // ignore empty messages 00566 if ( text.isEmpty() ) { 00567 return false; 00568 } 00569 00570 // display message box for specified event level 00571 switch( level ) { 00572 default: 00573 case KNotifyClient::Notification: 00574 KMessageBox::informationWId( winId, text, i18n("Notification"), 0, false ); 00575 break; 00576 case KNotifyClient::Warning: 00577 KMessageBox::sorryWId( winId, text, i18n("Warning"), false ); 00578 break; 00579 case KNotifyClient::Error: 00580 KMessageBox::errorWId( winId, text, i18n("Error"), false ); 00581 break; 00582 case KNotifyClient::Catastrophe: 00583 KMessageBox::errorWId( winId, text, i18n("Catastrophe!"), false ); 00584 break; 00585 } 00586 00587 return true; 00588 } 00589 00590 bool KNotify::notifyByPassivePopup( const TQString &text, 00591 const TQString &appName, 00592 TDEConfig* eventsFile, 00593 WId senderWinId ) 00594 { 00595 TDEIconLoader iconLoader( appName ); 00596 if ( eventsFile != NULL ) { 00597 TDEConfigGroup config( eventsFile, "!Global!" ); 00598 TQString iconName = config.readEntry( "IconName", appName ); 00599 TQPixmap icon = iconLoader.loadIcon( iconName, TDEIcon::Small ); 00600 TQString title = config.readEntry( "Comment", appName ); 00601 KPassivePopup::message(title, text, icon, senderWinId); 00602 } 00603 else { 00604 kdError() << "No events for app " << appName << "defined!" <<endl; 00605 } 00606 00607 return true; 00608 } 00609 00610 bool KNotify::notifyByExecute(const TQString &command, const TQString& event, 00611 const TQString& fromApp, const TQString& text, 00612 int winId, int eventId) { 00613 if (!command.isEmpty()) { 00614 // kdDebug() << "executing command '" << command << "'" << endl; 00615 TQMap<TQChar,TQString> subst; 00616 subst.insert( 'e', event ); 00617 subst.insert( 'a', fromApp ); 00618 subst.insert( 's', text ); 00619 subst.insert( 'w', TQString::number( winId )); 00620 subst.insert( 'i', TQString::number( eventId )); 00621 TQString execLine = KMacroExpander::expandMacrosShellQuote( command, subst ); 00622 if ( execLine.isEmpty() ) { 00623 execLine = command; // fallback 00624 } 00625 00626 TDEProcess p; 00627 p.setUseShell(true); 00628 p << execLine; 00629 p.start(TDEProcess::DontCare); 00630 return true; 00631 } 00632 return false; 00633 } 00634 00635 00636 bool KNotify::notifyByLogfile(const TQString &text, const TQString &file) 00637 { 00638 // ignore empty messages 00639 if ( text.isEmpty() ) { 00640 return true; 00641 } 00642 00643 // open file in append mode 00644 TQFile logFile(file); 00645 if ( !logFile.open(IO_WriteOnly | IO_Append) ) { 00646 return false; 00647 } 00648 00649 // append msg 00650 TQTextStream strm( &logFile ); 00651 strm << "- KNotify " << TQDateTime::currentDateTime().toString() << ": "; 00652 strm << text << endl; 00653 00654 // close file 00655 logFile.close(); 00656 return true; 00657 } 00658 00659 bool KNotify::notifyByStderr(const TQString &text) 00660 { 00661 // ignore empty messages 00662 if ( text.isEmpty() ) { 00663 return true; 00664 } 00665 00666 // open stderr for output 00667 TQTextStream strm( stderr, IO_WriteOnly ); 00668 00669 // output msg 00670 strm << "KNotify " << TQDateTime::currentDateTime().toString() << ": "; 00671 strm << text << endl; 00672 00673 return true; 00674 } 00675 00676 bool KNotify::notifyByTaskbar( WId win ) 00677 { 00678 if( win == 0 ) { 00679 return false; 00680 } 00681 KWin::demandAttention( win ); 00682 return true; 00683 } 00684 00685 bool KNotify::isGlobal(const TQString &eventname) 00686 { 00687 return d->globalEvents->hasGroup( eventname ); 00688 } 00689 00690 void KNotify::setVolume( int volume ) 00691 { 00692 if ( volume<0 ) volume=0; 00693 if ( volume>=100 ) volume=100; 00694 d->volume = volume; 00695 } 00696 00697 void KNotify::playTimeout() 00698 { 00699 #ifndef WITHOUT_ARTS 00700 for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it;) { 00701 TQPtrListIterator< KDE::PlayObject > current = it; 00702 ++it; 00703 if ( (*current)->state() != Arts::posPlaying ) { 00704 TQMap<KDE::PlayObject*,int>::Iterator eit = d->playObjectEventMap.find( *current ); 00705 if ( eit != d->playObjectEventMap.end() ) { 00706 soundFinished( *eit, PlayedOK ); 00707 d->playObjectEventMap.remove( eit ); 00708 } 00709 d->playObjects.remove( current ); 00710 } 00711 } 00712 if ( !d->playObjects.count() ) { 00713 d->playTimer->stop(); 00714 } 00715 #endif 00716 } 00717 00718 bool KNotify::isPlaying( const TQString& soundFile ) const 00719 { 00720 #ifndef WITHOUT_ARTS 00721 for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it; ++it) { 00722 if ( (*it)->mediaName() == soundFile ) { 00723 return true; 00724 } 00725 } 00726 #endif 00727 return false; 00728 } 00729 00730 void KNotify::slotPlayerProcessExited( TDEProcess *proc ) 00731 { 00732 soundFinished( d->externalPlayerEventId, (proc->normalExit() && proc->exitStatus() == 0) ? PlayedOK : Unknown ); 00733 } 00734 00735 void KNotify::abortFirstPlayObject() 00736 { 00737 #ifndef WITHOUT_ARTS 00738 TQMap<KDE::PlayObject*,int>::Iterator it = d->playObjectEventMap.find( d->playObjects.getFirst() ); 00739 if ( it != d->playObjectEventMap.end() ) { 00740 soundFinished( it.data(), Aborted ); 00741 d->playObjectEventMap.remove( it ); 00742 } 00743 d->playObjects.removeFirst(); 00744 #endif 00745 } 00746 00747 void KNotify::soundFinished( int eventId, PlayingFinishedStatus reason ) 00748 { 00749 TQByteArray data; 00750 TQDataStream stream( data, IO_WriteOnly ); 00751 stream << eventId << (int) reason; 00752 00753 DCOPClient::mainClient()->emitDCOPSignal( "KNotify", "playingFinished(int,int)", data ); 00754 } 00755 00756 WId KNotify::checkWinId( const TQString &appName, WId senderWinId ) 00757 { 00758 if ( senderWinId == 0 ) { 00759 TQCString senderId = kapp->dcopClient()->senderId(); 00760 TQCString compare = (appName + "-mainwindow").latin1(); 00761 int len = compare.length(); 00762 // kdDebug() << "notifyByPassivePopup: appName=" << appName << " sender=" << senderId << endl; 00763 00764 QCStringList objs = kapp->dcopClient()->remoteObjects( senderId ); 00765 for (QCStringList::ConstIterator it = objs.begin(); it != objs.end(); ++it ) { 00766 TQCString obj( *it ); 00767 if ( obj.left(len) == compare) { 00768 // kdDebug( ) << "found " << obj << endl; 00769 TQCString replyType; 00770 TQByteArray data, replyData; 00771 00772 if ( kapp->dcopClient()->call(senderId, obj, "getWinID()", data, replyType, replyData) ) { 00773 TQDataStream answer(replyData, IO_ReadOnly); 00774 if (replyType == "int") { 00775 answer >> senderWinId; 00776 // kdDebug() << "SUCCESS, found getWinID(): type='" << TQString(replyType) 00777 // << "' senderWinId=" << senderWinId << endl; 00778 } 00779 } 00780 } 00781 } 00782 } 00783 return senderWinId; 00784 } 00785 00786 void KNotify::restartedArtsd() 00787 { 00788 #ifndef WITHOUT_ARTS 00789 delete d->audioManager; 00790 d->audioManager = new KAudioManagerPlay( soundServer ); 00791 d->audioManager->setTitle( i18n( "Trinity System Notifications" ) ); 00792 d->audioManager->setAutoRestoreID( "KNotify Aman Play" ); 00793 #endif 00794 } 00795 00796 void KNotify::sessionReady() 00797 { 00798 if( d->inStartup && !d->startupEvents.isEmpty()) { 00799 kdDebug() << "There were knotify events while startup:" << d->startupEvents << endl; 00800 } 00801 d->inStartup = false; 00802 } 00803 00804 // vim: sw=4 sts=4 ts=8 et