TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

knotify.cpp 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /*
  2. Copyright (c) 1997 Christian Esken (esken@kde.org)
  3. 2000 Charles Samuels (charles@kde.org)
  4. 2000 Stefan Schimanski (1Stein@gmx.de)
  5. 2000 Matthias Ettrich (ettrich@kde.org)
  6. 2000 Waldo Bastian <bastian@kde.org>
  7. 2000-2003 Carsten Pfeiffer <pfeiffer@kde.org>
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2, or (at your option)
  11. any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. // C headers
  21. #include <fcntl.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <config.h>
  25. #ifndef WITHOUT_ARTS
  26. // aRts headers
  27. #include <connect.h>
  28. #include <dispatcher.h>
  29. #include <flowsystem.h>
  30. #include <qiomanager.h>
  31. #include <soundserver.h>
  32. #endif
  33. // QT headers
  34. #include <tqfile.h>
  35. #include <tqfileinfo.h>
  36. #include <tqstringlist.h>
  37. #include <tqtextstream.h>
  38. // KDE headers
  39. #include <dcopclient.h>
  40. #include <tdeaboutdata.h>
  41. #ifndef WITHOUT_ARTS
  42. #include <kartsdispatcher.h>
  43. #include <kartsserver.h>
  44. #endif
  45. #include <tdecmdlineargs.h>
  46. #include <tdeconfig.h>
  47. #include <kdebug.h>
  48. #include <tdeglobal.h>
  49. #include <tdelocale.h>
  50. #include <tdemessagebox.h>
  51. #include <kpassivepopup.h>
  52. #include <kiconloader.h>
  53. #include <kmacroexpander.h>
  54. #ifndef WITHOUT_ARTS
  55. #include <kplayobjectfactory.h>
  56. #include <kaudiomanagerplay.h>
  57. #endif
  58. #include <kprocess.h>
  59. #include <kstandarddirs.h>
  60. #include <kuniqueapplication.h>
  61. #include <twin.h>
  62. #include "knotify.h"
  63. #include "knotify.moc"
  64. class KNotifyPrivate
  65. {
  66. public:
  67. TDEConfig* globalEvents;
  68. TDEConfig* globalConfig;
  69. TQMap<TQString, TDEConfig*> events;
  70. TQMap<TQString, TDEConfig*> configs;
  71. TQString externalPlayer;
  72. TDEProcess *externalPlayerProc;
  73. #ifndef WITHOUT_ARTS
  74. TQPtrList<KDE::PlayObject> playObjects;
  75. TQMap<KDE::PlayObject*,int> playObjectEventMap;
  76. KAudioManagerPlay *audioManager;
  77. #endif
  78. int externalPlayerEventId;
  79. bool useExternal;
  80. bool useArts;
  81. int volume;
  82. TQTimer *playTimer;
  83. bool inStartup;
  84. TQString startupEvents;
  85. };
  86. // Yes, it's ugly to put this here, but this facilitates the cautious startup
  87. // procedure.
  88. #ifndef WITHOUT_ARTS
  89. KArtsServer *soundServer = 0;
  90. #endif
  91. extern "C"{
  92. KDE_EXPORT int kdemain(int argc, char **argv)
  93. {
  94. TDEAboutData aboutdata("knotify", I18N_NOOP("KNotify"),
  95. "3.0", I18N_NOOP("TDE Notification Server"),
  96. TDEAboutData::License_GPL, "(C) 1997-2003, KDE Developers");
  97. aboutdata.addAuthor("Carsten Pfeiffer",I18N_NOOP("Current Maintainer"),"pfeiffer@kde.org");
  98. aboutdata.addAuthor("Christian Esken",0,"esken@kde.org");
  99. aboutdata.addAuthor("Stefan Westerfeld",I18N_NOOP("Sound support"),"stefan@space.twc.de");
  100. aboutdata.addAuthor("Charles Samuels",I18N_NOOP("Previous Maintainer"),"charles@kde.org");
  101. TDECmdLineArgs::init( argc, argv, &aboutdata );
  102. KUniqueApplication::addCmdLineOptions();
  103. // initialize application
  104. if ( !KUniqueApplication::start() ) {
  105. kdDebug() << "Running knotify found" << endl;
  106. return 0;
  107. }
  108. KUniqueApplication app;
  109. app.disableSessionManagement();
  110. // KNotify is started on KDE startup and on demand (using
  111. // KNotifClient::startDaemon()) whenever a KNotify event occurs. Especially
  112. // KWin may fire many events (e.g. when a window pops up). When we have
  113. // problems with aRts or the installation, we might get an infinite loop
  114. // of knotify crashing, popping up the crashhandler window and twin firing
  115. // another event, starting knotify again...
  116. // We try to prevent this by tracking our startup and offer options to
  117. // abort this.
  118. #ifndef WITHOUT_ARTS
  119. TDEConfigGroup config( TDEGlobal::config(), "StartProgress" );
  120. TDEConfig artsKCMConfig( "kcmartsrc" );
  121. artsKCMConfig.setGroup( "Arts" );
  122. bool useArts = artsKCMConfig.readBoolEntry( "StartServer", true );
  123. if (useArts)
  124. useArts = config.readBoolEntry( "Use Arts", useArts );
  125. bool ok = config.readBoolEntry( "Arts Init", true );
  126. if ( useArts && !ok )
  127. {
  128. if ( KMessageBox::questionYesNo(
  129. 0L,
  130. i18n("During the previous startup, KNotify crashed while creating "
  131. "Arts::Dispatcher. Do you want to try again or disable "
  132. "aRts sound output?\n\n"
  133. "If you choose to disable aRts output now, you can re-enable "
  134. "it later or select an alternate sound player "
  135. "in the System Notifications control panel."),
  136. i18n("KNotify Problem"),
  137. i18n("&Try Again"),
  138. i18n("D&isable aRts Output"),
  139. "KNotifyStartProgress",
  140. 0 /* don't call KNotify :) */
  141. )
  142. == KMessageBox::No )
  143. {
  144. useArts = false;
  145. }
  146. }
  147. // when ArtsDispatcher crashes, we know it the next start.
  148. config.writeEntry( "Arts Init", false );
  149. config.writeEntry( "Use Arts", useArts );
  150. config.sync();
  151. KArtsDispatcher *dispatcher = 0;
  152. if ( useArts )
  153. {
  154. dispatcher = new KArtsDispatcher;
  155. soundServer = new KArtsServer;
  156. }
  157. // ok, seemed to work.
  158. config.writeEntry("Arts Init", useArts );
  159. config.sync();
  160. ok = config.readBoolEntry( "KNotify Init", true );
  161. if ( useArts && !ok )
  162. {
  163. if ( KMessageBox::questionYesNo(
  164. 0L,
  165. i18n("During the previous startup, KNotify crashed while instantiating "
  166. "KNotify. Do you want to try again or disable "
  167. "aRts sound output?\n\n"
  168. "If you choose to disable aRts output now, you can re-enable "
  169. "it later or select an alternate sound player "
  170. "in the System Notifications control panel."),
  171. i18n("KNotify Problem"),
  172. i18n("&Try Again"),
  173. i18n("D&isable aRts Output"),
  174. "KNotifyStartProgress",
  175. 0 /* don't call KNotify :) */
  176. )
  177. == KMessageBox::No )
  178. {
  179. useArts = false;
  180. delete soundServer;
  181. soundServer = 0L;
  182. delete dispatcher;
  183. dispatcher = 0L;
  184. }
  185. }
  186. // when KNotify instantiation crashes, we know it the next start.
  187. config.writeEntry( "KNotify Init", false );
  188. config.writeEntry( "Use Arts", useArts );
  189. config.sync();
  190. // start notify service
  191. KNotify *notify = new KNotify( useArts );
  192. config.writeEntry( "KNotify Init", true );
  193. config.sync();
  194. #else
  195. // start notify service, without aRts
  196. KNotify *notify = new KNotify( false );
  197. #endif
  198. app.dcopClient()->setDefaultObject( "Notify" );
  199. app.dcopClient()->setDaemonMode( true );
  200. // kdDebug() << "knotify starting" << endl;
  201. int ret = app.exec();
  202. delete notify;
  203. #ifndef WITHOUT_ARTS
  204. delete soundServer;
  205. delete dispatcher;
  206. #endif
  207. return ret;
  208. }
  209. }// end extern "C"
  210. KNotify::KNotify( bool useArts )
  211. : TQObject(), DCOPObject("Notify")
  212. {
  213. d = new KNotifyPrivate;
  214. d->globalEvents = new TDEConfig("knotify/eventsrc", true, false, "data");
  215. d->globalConfig = new TDEConfig("knotify.eventsrc", true, false);
  216. d->externalPlayerProc = 0;
  217. d->useArts = useArts;
  218. d->inStartup = true;
  219. #ifndef WITHOUT_ARTS
  220. d->playObjects.setAutoDelete(true);
  221. d->audioManager = 0;
  222. if( useArts )
  223. {
  224. connect( soundServer, TQT_SIGNAL( restartedServer() ), this, TQT_SLOT( restartedArtsd() ) );
  225. restartedArtsd(); //started allready need to initialize d->audioManager
  226. }
  227. #endif
  228. d->volume = 100;
  229. d->playTimer = 0;
  230. loadConfig();
  231. }
  232. KNotify::~KNotify()
  233. {
  234. reconfigure();
  235. #ifndef WITHOUT_ARTS
  236. d->playObjects.clear();
  237. delete d->globalEvents;
  238. delete d->globalConfig;
  239. delete d->externalPlayerProc;
  240. delete d->audioManager;
  241. #endif
  242. delete d;
  243. }
  244. void KNotify::loadConfig() {
  245. // load external player settings
  246. TDEConfig *kc = TDEGlobal::config();
  247. kc->setGroup("Misc");
  248. d->useExternal = kc->readBoolEntry( "Use external player", false );
  249. d->externalPlayer = kc->readPathEntry("External player");
  250. // try to locate a suitable player if none is configured
  251. if ( d->externalPlayer.isEmpty() ) {
  252. TQStringList players;
  253. players << "wavplay" << "aplay" << "auplay";
  254. TQStringList::Iterator it = players.begin();
  255. while ( d->externalPlayer.isEmpty() && it != players.end() ) {
  256. d->externalPlayer = TDEStandardDirs::findExe( *it );
  257. ++it;
  258. }
  259. }
  260. // load default volume
  261. d->volume = kc->readNumEntry( "Volume", 100 );
  262. }
  263. void KNotify::reconfigure()
  264. {
  265. kapp->config()->reparseConfiguration();
  266. loadConfig();
  267. // clear loaded config files
  268. d->globalConfig->reparseConfiguration();
  269. for ( TQMapIterator<TQString,TDEConfig*> it = d->configs.begin(); it != d->configs.end(); ++it )
  270. delete it.data();
  271. d->configs.clear();
  272. }
  273. void KNotify::notify(const TQString &event, const TQString &fromApp,
  274. const TQString &text, TQString sound, TQString file,
  275. int present, int level)
  276. {
  277. notify( event, fromApp, text, sound, file, present, level, 0, 1 );
  278. }
  279. void KNotify::notify(const TQString &event, const TQString &fromApp,
  280. const TQString &text, TQString sound, TQString file,
  281. int present, int level, int winId)
  282. {
  283. notify( event, fromApp, text, sound, file, present, level, winId, 1 );
  284. }
  285. void KNotify::notify(const TQString &event, const TQString &fromApp,
  286. const TQString &text, TQString sound, TQString file,
  287. int present, int level, int winId, int eventId )
  288. {
  289. // kdDebug() << "event=" << event << " fromApp=" << fromApp << " text=" << text << " sound=" << sound <<
  290. // " file=" << file << " present=" << present << " level=" << level << " winId=" << winId << " eventId=" << eventId << endl;
  291. if( d->inStartup ) {
  292. d->startupEvents += "(" + event + ":" + fromApp + ")";
  293. }
  294. TQString commandline;
  295. TDEConfig *eventsFile = NULL;
  296. TDEConfig *configFile = NULL;
  297. // check for valid events
  298. if ( !event.isEmpty() ) {
  299. // get config file
  300. if ( d->events.contains( fromApp ) ) {
  301. eventsFile = d->events[fromApp];
  302. } else {
  303. eventsFile=new TDEConfig(locate("data", fromApp+"/eventsrc"),true,false);
  304. d->events.insert( fromApp, eventsFile );
  305. }
  306. if ( d->configs.contains( fromApp) ) {
  307. configFile = d->configs[fromApp];
  308. } else {
  309. configFile=new TDEConfig(fromApp+".eventsrc",true,false);
  310. d->configs.insert( fromApp, configFile );
  311. }
  312. if ( !eventsFile->hasGroup( event ) && isGlobal(event) )
  313. {
  314. eventsFile = d->globalEvents;
  315. configFile = d->globalConfig;
  316. }
  317. eventsFile->setGroup( event );
  318. configFile->setGroup( event );
  319. // get event presentation
  320. if ( present==-1 )
  321. present = configFile->readNumEntry( "presentation", -1 );
  322. if ( present==-1 )
  323. present = eventsFile->readNumEntry( "default_presentation", 0 );
  324. // get sound file name
  325. if( present & KNotifyClient::Sound ) {
  326. TQString theSound = configFile->readPathEntry( "soundfile" );
  327. if ( theSound.isEmpty() )
  328. theSound = eventsFile->readPathEntry( "default_sound" );
  329. if ( !theSound.isEmpty() )
  330. sound = theSound;
  331. }
  332. // get log file name
  333. if( present & KNotifyClient::Logfile ) {
  334. TQString theFile = configFile->readPathEntry( "logfile" );
  335. if ( theFile.isEmpty() )
  336. theFile = eventsFile->readPathEntry( "default_logfile" );
  337. if ( !theFile.isEmpty() )
  338. file = theFile;
  339. }
  340. // get default event level
  341. if( present & KNotifyClient::Messagebox )
  342. level = eventsFile->readNumEntry( "level", 0 );
  343. // get command line
  344. if (present & KNotifyClient::Execute ) {
  345. commandline = configFile->readPathEntry( "commandline" );
  346. if ( commandline.isEmpty() )
  347. commandline = eventsFile->readPathEntry( "default_commandline" );
  348. }
  349. }
  350. // emit event
  351. if ( present & KNotifyClient::Sound ) // && TQFile(sound).isReadable()
  352. notifyBySound( sound, fromApp, eventId );
  353. if ( present & KNotifyClient::Execute )
  354. notifyByExecute( commandline, event, fromApp, text, winId, eventId );
  355. if ( present & KNotifyClient::Logfile ) // && TQFile(file).isWritable()
  356. notifyByLogfile( text, file );
  357. if ( present & KNotifyClient::Stderr )
  358. notifyByStderr( text );
  359. if ( present & KNotifyClient::Taskbar )
  360. notifyByTaskbar( checkWinId( fromApp, winId ));
  361. if ( present & KNotifyClient::PassivePopup )
  362. notifyByPassivePopup( text, fromApp, eventsFile, checkWinId( fromApp, winId ));
  363. else if ( present & KNotifyClient::Messagebox )
  364. notifyByMessagebox( text, level, checkWinId( fromApp, winId ));
  365. TQByteArray qbd;
  366. TQDataStream ds(qbd, IO_WriteOnly);
  367. ds << event << fromApp << text << sound << file << present << level
  368. << winId << eventId;
  369. emitDCOPSignal("notifySignal(TQString,TQString,TQString,TQString,TQString,int,int,int,int)", qbd);
  370. }
  371. bool KNotify::notifyBySound( const TQString &sound, const TQString &appname, int eventId )
  372. {
  373. if (sound.isEmpty()) {
  374. soundFinished( eventId, NoSoundFile );
  375. return false;
  376. }
  377. bool external = d->useExternal && !d->externalPlayer.isEmpty();
  378. // get file name
  379. TQString soundFile(sound);
  380. if ( TQFileInfo(sound).isRelative() )
  381. {
  382. TQString search = TQString("%1/sounds/%2").arg(appname).arg(sound);
  383. soundFile = TDEGlobal::instance()->dirs()->findResource("data", search);
  384. if ( soundFile.isEmpty() )
  385. soundFile = locate( "sound", sound );
  386. }
  387. if ( soundFile.isEmpty() || isPlaying( soundFile ) )
  388. {
  389. soundFinished( eventId, soundFile.isEmpty() ? NoSoundFile : FileAlreadyPlaying );
  390. return false;
  391. }
  392. // kdDebug() << "KNotify::notifyBySound - trying to play file " << soundFile << endl;
  393. if (!external) {
  394. //If we disabled using aRts, just return,
  395. //(If we don't, we'll blow up accessing the null soundServer)
  396. if (!d->useArts)
  397. {
  398. soundFinished( eventId, NoSoundSupport );
  399. return false;
  400. }
  401. #ifndef WITHOUT_ARTS
  402. // play sound finally
  403. while( d->playObjects.count()>5 )
  404. abortFirstPlayObject();
  405. KDE::PlayObjectFactory factory(soundServer->server());
  406. if( d->audioManager )
  407. factory.setAudioManagerPlay( d->audioManager );
  408. KURL soundURL;
  409. soundURL.setPath(soundFile);
  410. KDE::PlayObject *playObject = factory.createPlayObject(soundURL, false);
  411. if (playObject->isNull())
  412. {
  413. soundFinished( eventId, NoSoundSupport );
  414. delete playObject;
  415. return false;
  416. }
  417. if ( d->volume != 100 )
  418. {
  419. // It works to access the playObject immediately because we don't allow
  420. // non-file URLs for sounds.
  421. Arts::StereoVolumeControl volumeControl = Arts::DynamicCast(soundServer->server().createObject("Arts::StereoVolumeControl"));
  422. Arts::PlayObject player = playObject->object();
  423. Arts::Synth_AMAN_PLAY ap = d->audioManager->amanPlay();
  424. if( ! volumeControl.isNull() && ! player.isNull() && ! ap.isNull() )
  425. {
  426. volumeControl.scaleFactor( d->volume/100.0 );
  427. ap.stop();
  428. Arts::disconnect( player, "left", ap, "left" );
  429. Arts::disconnect( player, "right", ap, "right" );
  430. ap.start();
  431. volumeControl.start();
  432. Arts::connect(player,"left",volumeControl,"inleft");
  433. Arts::connect(player,"right",volumeControl,"inright");
  434. Arts::connect(volumeControl,"outleft",ap,"left");
  435. Arts::connect(volumeControl,"outright",ap,"right");
  436. player._addChild( volumeControl, "volume" );
  437. }
  438. }
  439. playObject->play();
  440. d->playObjects.append( playObject );
  441. d->playObjectEventMap.insert( playObject, eventId );
  442. if ( !d->playTimer )
  443. {
  444. d->playTimer = new TQTimer( this );
  445. connect( d->playTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( playTimeout() ) );
  446. }
  447. if ( !d->playTimer->isActive() )
  448. d->playTimer->start( 1000 );
  449. #endif
  450. return true;
  451. } else if(!d->externalPlayer.isEmpty()) {
  452. // use an external player to play the sound
  453. TDEProcess *proc = d->externalPlayerProc;
  454. if (!proc)
  455. {
  456. proc = d->externalPlayerProc = new TDEProcess;
  457. connect( proc, TQT_SIGNAL( processExited( TDEProcess * )),
  458. TQT_SLOT( slotPlayerProcessExited( TDEProcess * )));
  459. }
  460. if (proc->isRunning())
  461. {
  462. soundFinished( eventId, PlayerBusy );
  463. return false; // Skip
  464. }
  465. proc->clearArguments();
  466. (*proc) << d->externalPlayer << TQFile::encodeName( soundFile ).data();
  467. d->externalPlayerEventId = eventId;
  468. proc->start(TDEProcess::NotifyOnExit);
  469. return true;
  470. }
  471. soundFinished( eventId, Unknown );
  472. return false;
  473. }
  474. bool KNotify::notifyByMessagebox(const TQString &text, int level, WId winId)
  475. {
  476. // ignore empty messages
  477. if ( text.isEmpty() )
  478. return false;
  479. // display message box for specified event level
  480. switch( level ) {
  481. default:
  482. case KNotifyClient::Notification:
  483. KMessageBox::informationWId( winId, text, i18n("Notification"), 0, false );
  484. break;
  485. case KNotifyClient::Warning:
  486. KMessageBox::sorryWId( winId, text, i18n("Warning"), false );
  487. break;
  488. case KNotifyClient::Error:
  489. KMessageBox::errorWId( winId, text, i18n("Error"), false );
  490. break;
  491. case KNotifyClient::Catastrophe:
  492. KMessageBox::errorWId( winId, text, i18n("Catastrophe!"), false );
  493. break;
  494. }
  495. return true;
  496. }
  497. bool KNotify::notifyByPassivePopup( const TQString &text,
  498. const TQString &appName,
  499. TDEConfig* eventsFile,
  500. WId senderWinId )
  501. {
  502. TDEIconLoader iconLoader( appName );
  503. if ( eventsFile != NULL ) {
  504. TDEConfigGroup config( eventsFile, "!Global!" );
  505. TQString iconName = config.readEntry( "IconName", appName );
  506. TQPixmap icon = iconLoader.loadIcon( iconName, TDEIcon::Small );
  507. TQString title = config.readEntry( "Comment", appName );
  508. KPassivePopup::message(title, text, icon, senderWinId);
  509. } else
  510. kdError() << "No events for app " << appName << "defined!" <<endl;
  511. return true;
  512. }
  513. bool KNotify::notifyByExecute(const TQString &command, const TQString& event,
  514. const TQString& fromApp, const TQString& text,
  515. int winId, int eventId) {
  516. if (!command.isEmpty()) {
  517. // kdDebug() << "executing command '" << command << "'" << endl;
  518. TQMap<TQChar,TQString> subst;
  519. subst.insert( 'e', event );
  520. subst.insert( 'a', fromApp );
  521. subst.insert( 's', text );
  522. subst.insert( 'w', TQString::number( winId ));
  523. subst.insert( 'i', TQString::number( eventId ));
  524. TQString execLine = KMacroExpander::expandMacrosShellQuote( command, subst );
  525. if ( execLine.isEmpty() )
  526. execLine = command; // fallback
  527. TDEProcess p;
  528. p.setUseShell(true);
  529. p << execLine;
  530. p.start(TDEProcess::DontCare);
  531. return true;
  532. }
  533. return false;
  534. }
  535. bool KNotify::notifyByLogfile(const TQString &text, const TQString &file)
  536. {
  537. // ignore empty messages
  538. if ( text.isEmpty() )
  539. return true;
  540. // open file in append mode
  541. TQFile logFile(file);
  542. if ( !logFile.open(IO_WriteOnly | IO_Append) )
  543. return false;
  544. // append msg
  545. TQTextStream strm( &logFile );
  546. strm << "- KNotify " << TQDateTime::currentDateTime().toString() << ": ";
  547. strm << text << endl;
  548. // close file
  549. logFile.close();
  550. return true;
  551. }
  552. bool KNotify::notifyByStderr(const TQString &text)
  553. {
  554. // ignore empty messages
  555. if ( text.isEmpty() )
  556. return true;
  557. // open stderr for output
  558. TQTextStream strm( stderr, IO_WriteOnly );
  559. // output msg
  560. strm << "KNotify " << TQDateTime::currentDateTime().toString() << ": ";
  561. strm << text << endl;
  562. return true;
  563. }
  564. bool KNotify::notifyByTaskbar( WId win )
  565. {
  566. if( win == 0 )
  567. return false;
  568. KWin::demandAttention( win );
  569. return true;
  570. }
  571. bool KNotify::isGlobal(const TQString &eventname)
  572. {
  573. return d->globalEvents->hasGroup( eventname );
  574. }
  575. void KNotify::setVolume( int volume )
  576. {
  577. if ( volume<0 ) volume=0;
  578. if ( volume>=100 ) volume=100;
  579. d->volume = volume;
  580. }
  581. void KNotify::playTimeout()
  582. {
  583. #ifndef WITHOUT_ARTS
  584. for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it;)
  585. {
  586. TQPtrListIterator< KDE::PlayObject > current = it;
  587. ++it;
  588. if ( (*current)->state() != Arts::posPlaying )
  589. {
  590. TQMap<KDE::PlayObject*,int>::Iterator eit = d->playObjectEventMap.find( *current );
  591. if ( eit != d->playObjectEventMap.end() )
  592. {
  593. soundFinished( *eit, PlayedOK );
  594. d->playObjectEventMap.remove( eit );
  595. }
  596. d->playObjects.remove( current );
  597. }
  598. }
  599. if ( !d->playObjects.count() )
  600. d->playTimer->stop();
  601. #endif
  602. }
  603. bool KNotify::isPlaying( const TQString& soundFile ) const
  604. {
  605. #ifndef WITHOUT_ARTS
  606. for ( TQPtrListIterator< KDE::PlayObject > it(d->playObjects); *it; ++it)
  607. {
  608. if ( (*it)->mediaName() == soundFile )
  609. return true;
  610. }
  611. #endif
  612. return false;
  613. }
  614. void KNotify::slotPlayerProcessExited( TDEProcess *proc )
  615. {
  616. soundFinished( d->externalPlayerEventId,
  617. (proc->normalExit() && proc->exitStatus() == 0) ? PlayedOK : Unknown );
  618. }
  619. void KNotify::abortFirstPlayObject()
  620. {
  621. #ifndef WITHOUT_ARTS
  622. TQMap<KDE::PlayObject*,int>::Iterator it = d->playObjectEventMap.find( d->playObjects.getFirst() );
  623. if ( it != d->playObjectEventMap.end() )
  624. {
  625. soundFinished( it.data(), Aborted );
  626. d->playObjectEventMap.remove( it );
  627. }
  628. d->playObjects.removeFirst();
  629. #endif
  630. }
  631. void KNotify::soundFinished( int eventId, PlayingFinishedStatus reason )
  632. {
  633. TQByteArray data;
  634. TQDataStream stream( data, IO_WriteOnly );
  635. stream << eventId << (int) reason;
  636. DCOPClient::mainClient()->emitDCOPSignal( "KNotify", "playingFinished(int,int)", data );
  637. }
  638. WId KNotify::checkWinId( const TQString &appName, WId senderWinId )
  639. {
  640. if ( senderWinId == 0 )
  641. {
  642. TQCString senderId = kapp->dcopClient()->senderId();
  643. TQCString compare = (appName + "-mainwindow").latin1();
  644. int len = compare.length();
  645. // kdDebug() << "notifyByPassivePopup: appName=" << appName << " sender=" << senderId << endl;
  646. QCStringList objs = kapp->dcopClient()->remoteObjects( senderId );
  647. for (QCStringList::ConstIterator it = objs.begin(); it != objs.end(); ++it ) {
  648. TQCString obj( *it );
  649. if ( obj.left(len) == compare) {
  650. // kdDebug( ) << "found " << obj << endl;
  651. TQCString replyType;
  652. TQByteArray data, replyData;
  653. if ( kapp->dcopClient()->call(senderId, obj, "getWinID()", data, replyType, replyData) ) {
  654. TQDataStream answer(replyData, IO_ReadOnly);
  655. if (replyType == "int") {
  656. answer >> senderWinId;
  657. // kdDebug() << "SUCCESS, found getWinID(): type='" << TQString(replyType)
  658. // << "' senderWinId=" << senderWinId << endl;
  659. }
  660. }
  661. }
  662. }
  663. }
  664. return senderWinId;
  665. }
  666. void KNotify::restartedArtsd()
  667. {
  668. #ifndef WITHOUT_ARTS
  669. delete d->audioManager;
  670. d->audioManager = new KAudioManagerPlay( soundServer );
  671. d->audioManager->setTitle( i18n( "Trinity System Notifications" ) );
  672. d->audioManager->setAutoRestoreID( "KNotify Aman Play" );
  673. #endif
  674. }
  675. void KNotify::sessionReady()
  676. {
  677. if( d->inStartup && !d->startupEvents.isEmpty())
  678. kdDebug() << "There were knotify events while startup:" << d->startupEvents << endl;
  679. d->inStartup = false;
  680. }
  681. // vim: sw=4 sts=4 ts=8 et