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