diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /arts | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'arts')
53 files changed, 6426 insertions, 0 deletions
diff --git a/arts/Makefile.am b/arts/Makefile.am new file mode 100644 index 000000000..31bd7bbbd --- /dev/null +++ b/arts/Makefile.am @@ -0,0 +1,9 @@ +if include_ARTS +SUBDIRS = kde knotify message +else +SUBDIRS = knotify +endif + +DOXYGEN_REFERENCES = kio kdecore kdeui +include ../admin/Doxyfile.am + diff --git a/arts/configure.in.in b/arts/configure.in.in new file mode 100644 index 000000000..6571c8b68 --- /dev/null +++ b/arts/configure.in.in @@ -0,0 +1,75 @@ + +dnl aRts specific configure tests +dnl + +dnl +dnl ensure that the user has aRts-1.1.0 or newer installed +dnl + +dnl Check for artsc-config +dnl no need to, AC_BASE_PATH_KDE does it for us already (see also +dnl comment below for mcopidl) +dnl AC_PATH_PROG(ARTSCCONFIG, artsc-config, no) + +ARTS_WANT_VERSION_MAJOR=1 +ARTS_WANT_VERSION_MINOR=1 +ARTS_HAVE_VERSION=none +ARTS_HAVE_PREFIX=none + +dnl Check for Glib-2.0 +AC_MSG_CHECKING(for aRts-$ARTS_WANT_VERSION_MAJOR.$ARTS_WANT_VERSION_MINOR) + +ARTS_OK=no + +if test "$build_arts" != "yes"; then + AC_MSG_RESULT(disabled) +else + + if test "x$ARTSCCONFIG" != "xno"; then + ARTS_HAVE_VERSION=`$ARTSCCONFIG --arts-version` + ARTS_HAVE_PREFIX=`$ARTSCCONFIG --arts-prefix` + fi + + # And delete superfluous '/' to make compares easier + ARTS_HAVE_PREFIX=`echo "$ARTS_HAVE_PREFIX" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + ARTS_MAJOR=`echo $ARTS_HAVE_VERSION | sed 's/\.[[0-9]]*\.[[0-9]]*$//'` + ARTS_MINOR=`echo $ARTS_HAVE_VERSION | sed 's/\.[[0-9]]*$//' | sed 's/^[[0-9]]*\.//'` + dnl don't look at the micro version + if test "x$ARTS_MAJOR" != "x" && test "x$ARTS_MINOR" != "x" && test $ARTS_MAJOR -ge $ARTS_WANT_VERSION_MAJOR && test $ARTS_MINOR -ge $ARTS_WANT_VERSION_MINOR; then + realartsprefix=`(cd $ARTS_HAVE_PREFIX; /bin/pwd)` + realprefix=`(cd $prefix; /bin/pwd)` + if test "x$realartsprefix" = "x$realprefix"; then + ARTS_OK=yes + else + AC_MSG_ERROR([aRts $ARTS_WANT_VERSION_MAJOR.$ARTS_WANT_VERSION_MINOR not installed in the same prefix as KDE! +Please reinstall aRts in the same prefix as KDE, different prefixes are not +supported right now. + +(kdelibs prefix is $prefix, aRts prefix is $ARTS_HAVE_PREFIX) + ]) + fi + fi + + AC_MSG_RESULT($ARTS_OK) + + if test "x$ARTS_OK" = "xno"; then + AC_MSG_ERROR([aRts $ARTS_WANT_VERSION_MAJOR.$ARTS_WANT_VERSION_MINOR not found. + +You'll need to install a suitable version of aRts in the same prefix as KDE +before you build kdelibs. + +(found + * artsc-config: $ARTSCCONFIG + * kdelibs prefix: $prefix + * aRts prefix: $ARTS_HAVE_PREFIX + * aRts version: $ARTS_HAVE_VERSION (required: $ARTS_WANT_VERSION_MAJOR.$ARTS_WANT_VERSION_MINOR) +) +]) + fi +fi + +dnl AC_BASE_PATH_KDE already checks for mcopidl, and it does it the +dnl right way using KDE_FIND_PATH +dnl AC_PATH_PROG(MCOPIDL, mcopidl, no) +dnl AC_SUBST(MCOPIDL) diff --git a/arts/kde/Makefile.am b/arts/kde/Makefile.am new file mode 100644 index 000000000..5a933ba68 --- /dev/null +++ b/arts/kde/Makefile.am @@ -0,0 +1,40 @@ +INCLUDES = -I$(top_builddir)/arts/kde \ + -I$(top_srcdir) -I$(includedir)/arts $(all_includes) + +lib_LTLIBRARIES = libartskde.la +libartskde_la_SOURCES = artskde.cc kioinputstream_impl.cpp kplayobject.cc \ + kplayobjectfactory.cc kartsfloatwatch.cpp kartsdispatcher.cc \ + kaudiorecordstream.cpp kaudioplaystream.cpp \ + kartsserver.cpp kdatarequest_impl.cpp kaudioconverter.cc \ + kvideowidget.cpp kplayobjectcreator.cc \ + kaudiomanagerplay.cpp +libartskde_la_LIBADD = $(LIB_KIO) -lqtmcop -lsoundserver_idl +libartskde_la_LDFLAGS = $(all_libraries) -no-undefined -version-info 3:0:2 +libartskde_la_METASOURCES = AUTO +libartskde_la_COMPILE_FIRST = artskde.h + +artskdeincludedir = $(includedir)/arts +artskdeinclude_HEADERS = kplayobject.h kplayobjectfactory.h kartsfloatwatch.h \ + artskde.h kartsdispatcher.h \ + kaudiorecordstream.h kaudioplaystream.h \ + kartsserver.h kvideowidget.h kaudiomanagerplay.h +noinst_HEADERS = kplayobjectcreator.h kplayobjectfactory_p.h + +artskde.mcoptype: artskde.h +artskde.mcopclass: artskde.h +MCOPINC = -I$(srcdir) +artskde.cc artskde.h: $(top_srcdir)/arts/kde/artskde.idl $(MCOPIDL) + $(MCOPIDL) -I$(includedir)/arts -t $(MCOPINC) $(top_srcdir)/arts/kde/artskde.idl + +DISTCLEANFILES = artskde.cc artskde.h artskde.mcoptype artskde.mcopclass + +check_PROGRAMS = kiotest kiotestslow kconverttest +kiotest_SOURCES = kiotest.cc +kiotestslow_SOURCES = kiotestslow.cc +kconverttest_SOURCES = kconverttest.cc + +kiotest_LDADD = libartskde.la -lqtmcop -lkmedia2 -lsoundserver_idl +kiotestslow_LDADD = $(kiotest_LDADD) +kconverttest_LDADD = $(kiotest_LDADD) + +# vim: ts=8 noet diff --git a/arts/kde/README b/arts/kde/README new file mode 100644 index 000000000..2d34f08fd --- /dev/null +++ b/arts/kde/README @@ -0,0 +1,51 @@ +libartskde Introduction +----------------------- + +1. What is libartskde? +libartskde is a simple KDE->aRts wrapper +that allows the developer to use KDE +technology to access aRts. +ie. no need to deal with std::string's anymore +etc.. you can just use QString's or KURL's +to play sound + +2. How to use it to play sounds? +<snip> +1 KArtsDispatcher dispatcher; +2 KArtsServer server; + +3 KURL file = "file:/home/nikoz/test.mp3"; + +4 KPlayObjectFactory factory(server.server()); +5 KPlayObject *playobj = factory.createPlayObject(file, true); + +6 playobj->play(); +<snap> + +Line: +1 Sets up the a KArtsDispatcher +2 Starts a new SoundServerV2 in the running artsd process + +3 Simple test URL to demonstrate the use with KURL + +4 Creates a KPlayObjectFactory, parameter: our SoundServerV2 +5 Gets a KPlayObject from the factory, containing an Arts::PlayObject + created in our running artsd process + Parameters: + KURL url + (specifies the url to be played) + bool createBUS + (specifies wheter to create a Synth_BUS_UPLINK or not, "false" is only interesting if you want to use EffectsStacks etc..., see Noatun) +6 Play the file + +That's it, with 6 LOC a "full" media player :) + +To make the example above compile you will also have to add these #includes: +#include <arts/kartsserver.h> +#include <arts/kartsdispatcher.h> +#include <arts/kplayobject.h> +#include <arts/kplayobjectfactory.h> + +Enjoy... +Nikolas Zimmermann +<wildfox@kde.org> diff --git a/arts/kde/artskde.idl b/arts/kde/artskde.idl new file mode 100644 index 000000000..f31b49ed4 --- /dev/null +++ b/arts/kde/artskde.idl @@ -0,0 +1,41 @@ +#include <kmedia2.idl> + +module Arts { + +/* + * notification proxy for floats, used internally! + */ +interface KFloatWatchProxy { + attribute float value; +}; + +/* + * used for deliviering MCOP data to the playobjects + */ +interface KIOInputStream : InputStream { + boolean openURL(string url); + + attribute long bufferPackets; + + long packetSize(); +}; + +/* + * used for piping raw data to KAudioConverter from the POs + */ +interface KDataRequest : SynthModule { + void goOn(); + + default in audio stream left, right; +}; + +/* + * TESTING ONLY + */ + +interface KIOTestSlow : SynthModule { + async in byte stream data; + + attribute InputStream inputStream; +}; +}; diff --git a/arts/kde/kartsdispatcher.cc b/arts/kde/kartsdispatcher.cc new file mode 100644 index 000000000..e6136ce12 --- /dev/null +++ b/arts/kde/kartsdispatcher.cc @@ -0,0 +1,60 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include <qiomanager.h> +#include <dispatcher.h> + +#include <kdebug.h> + +#include "kartsdispatcher.moc" + +int KArtsDispatcher::m_refCount = 0; +Arts::Dispatcher *KArtsDispatcher::artsDispatcher = 0; +Arts::QIOManager *KArtsDispatcher::artsQIOManager = 0; + +KArtsDispatcher::KArtsDispatcher(QObject *parent, const char *name) + : QObject(parent, name) +{ + m_refCount++; + if(artsDispatcher == 0) + { + if (!Arts::Dispatcher::the()) // only if no Arts::Dispatcher is created yet + { + artsQIOManager = new Arts::QIOManager(); + artsDispatcher = new Arts::Dispatcher(artsQIOManager); + } + else + kdWarning(400) << "An Arts::Dispatcher() instance exists already while trying to instantiate KArtsDispatcher!" << endl; + } +} + +KArtsDispatcher::~KArtsDispatcher() +{ + m_refCount--; + if(m_refCount == 0) + { + delete KArtsDispatcher::artsDispatcher; + artsDispatcher = 0; + + delete KArtsDispatcher::artsQIOManager; + artsQIOManager = 0; + } +} diff --git a/arts/kde/kartsdispatcher.h b/arts/kde/kartsdispatcher.h new file mode 100644 index 000000000..db2792a97 --- /dev/null +++ b/arts/kde/kartsdispatcher.h @@ -0,0 +1,87 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KARTSDISPATCHER_H +#define KARTSDISPATCHER_H + +#include <qobject.h> + +#include <kdelibs_export.h> + +namespace Arts +{ + class QIOManager; + class Dispatcher; +} + +/** + * KArtsDispatcher ensures that an instance of Arts::Dispatcher using an + * Arts::QIOManager exists. When the last KArtsDispatcher is deleted, the + * Arts::Dispatcher is released as well. + * + * Using KArtsDispatcher is especially useful in setups where another plugin + * might also already use an Arts::Dispatcher, for instance in konqueror. + * + * \code + * { + * // old code + * Arts::QIOManager qiomanager; + * Arts::Dispatcher dispatcher(&qiomanager); + * + * Arts::SoundServer server = Arts::Reference("global:Arts_SoundServer"); + * server.play("/usr/share/sounds/pop.wav"); + * } + * \endcode + * + * \code + * { + * // new code + * KArtsDispatcher dispatcher; + * + * Arts::SoundServer server = Arts::Reference("global:Arts_SoundServer"); + * server.play("/usr/share/sounds/pop.wav"); + * } + * \endcode + */ +class KDE_EXPORT KArtsDispatcher : public QObject +{ +Q_OBJECT +public: + /** + * Constructor. + * + * @param parent the parent Qt object + * @param name the Qt object name of this object + */ + KArtsDispatcher(QObject *parent = 0, const char *name = 0); + + /** + * Destructor + */ + ~KArtsDispatcher(); + +private: + static int m_refCount; + static Arts::Dispatcher *artsDispatcher; + static Arts::QIOManager *artsQIOManager; +}; + +#endif diff --git a/arts/kde/kartsfloatwatch.cpp b/arts/kde/kartsfloatwatch.cpp new file mode 100644 index 000000000..d26d76718 --- /dev/null +++ b/arts/kde/kartsfloatwatch.cpp @@ -0,0 +1,64 @@ + /* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "artskde.h" +#include "kartsfloatwatch.moc" +#include "connect.h" + +using namespace Arts; + +class KArtsFloatWatchPrivate { +public: + KFloatWatchProxy proxy; +}; + +namespace Arts { + +class KFloatWatchProxy_impl : public KFloatWatchProxy_skel { +protected: + KArtsFloatWatch *watch; +public: + KFloatWatchProxy_impl(KArtsFloatWatch *watch) : watch(watch) { }; + + float value() { return 0.0; /* dummy */ } + void value(float newValue) { watch->change(newValue); } +}; + +} + +KArtsFloatWatch::KArtsFloatWatch(Arts::Object object, const char *stream, + QObject *parent, const char *name) : QObject(parent, name) +{ + d = new KArtsFloatWatchPrivate(); + d->proxy = KFloatWatchProxy::_from_base(new KFloatWatchProxy_impl(this)); + Arts::connect(object, stream, d->proxy, "value"); +} + +KArtsFloatWatch::~KArtsFloatWatch() +{ + delete d; +} + +void KArtsFloatWatch::change(float newValue) +{ + emit valueChanged(newValue); +} diff --git a/arts/kde/kartsfloatwatch.h b/arts/kde/kartsfloatwatch.h new file mode 100644 index 000000000..6c23327ea --- /dev/null +++ b/arts/kde/kartsfloatwatch.h @@ -0,0 +1,82 @@ + /* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "common.h" +#include <qobject.h> + +class KArtsFloatWatchPrivate; +namespace Arts { class KFloatWatchProxy_impl; } + +/** + * KArtsFloatWatch offers an easy way to watch aRts streams via Qt signals. + * For instance, if you have an object of the following type: + * + * \code + * interface StereoVolumeControl : StereoEffect { + * attribute float scaleFactor; + * readonly attribute float currentVolumeLeft; + * readonly attribute float currentVolumeRight; + * }; + * \endcode + * + * and you want to get notified when scaleFactor changes, you could do it + * like this: + * + * \code + * StereoVolumeControl stereoVolumeControl = ...; + * KArtsFloatWatch *w = new KArtsFloatWatch(stereoVolumeControl, "scaleFactor_changed", this); + * connect(w, SIGNAL(valueChanged(float)), this, SLOT(setValue(float))); + * \endcode + */ +class KArtsFloatWatch : public QObject { + Q_OBJECT +private: + KArtsFloatWatchPrivate *d; + friend class Arts::KFloatWatchProxy_impl; + + /** + * called by the proxy (internal) + */ + void change(float newValue); + +public: + /** + * Constructor. + * + * @param object the aRts object that should be watched + * @param stream the aRts stream that should be watched + * @param parent the parent Qt object + * @param name the Qt object name of this object + */ + KArtsFloatWatch(Arts::Object object, const char *stream, QObject *parent = 0, const char *name = 0); + + /** + * Destructor + */ + ~KArtsFloatWatch(); + +signals: + /** + * this signal will be emitted with values of the aRts stream + */ + void valueChanged(float newValue); +}; diff --git a/arts/kde/kartsserver.cpp b/arts/kde/kartsserver.cpp new file mode 100644 index 000000000..9b4739928 --- /dev/null +++ b/arts/kde/kartsserver.cpp @@ -0,0 +1,111 @@ +// Copyright (c) 2000-2001 Charles Samuels <charles@kde.org> +// Neil Stevens <neil@qualityassistant.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIAB\ILITY, WHETHER IN +// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include <flowsystem.h> +#include <ksimpleconfig.h> +#include <kprocess.h> +#include <kstandarddirs.h> +#include <qdir.h> +#include <qfile.h> +#include "kartsserver.h" + +struct KArtsServer::Data +{ + Arts::SoundServerV2 server; +}; + +KArtsServer::KArtsServer(QObject *parent, const char *name) + : QObject(parent, name) + , d(new Data) +{ + d->server = Arts::SoundServerV2::null(); +} + +KArtsServer::~KArtsServer(void) +{ + d->server = Arts::SoundServerV2::null(); + delete d; +} + +Arts::SoundServerV2 KArtsServer::server(void) +{ + bool error = d->server.error(); + if( d->server.isNull() || error ) + { + d->server = Arts::Reference("global:Arts_SoundServerV2"); + if( error && !d->server.isNull() && !d->server.error() ) + emit restartedServer(); + } + + if(!d->server.isNull() && !d->server.error()) + return d->server; + + // aRts seems not to be running, let's try to run it + // First, let's read the configuration as in kcmarts + KConfig config("kcmartsrc", false /*bReadOnly*/, false /*bUseKDEGlobals*/); + KProcess proc; + + config.setGroup("Arts"); + + bool rt = config.readBoolEntry("StartRealtime", false); + bool x11Comm = config.readBoolEntry("X11GlobalComm", false); + + // put the value of x11Comm into .mcoprc + KSimpleConfig X11CommConfig(QDir::homeDirPath()+"/.mcoprc"); + + if(x11Comm) + X11CommConfig.writeEntry("GlobalComm", "Arts::X11GlobalComm"); + else + X11CommConfig.writeEntry("GlobalComm", "Arts::TmpGlobalComm"); + + X11CommConfig.sync(); + + proc << QFile::encodeName(KStandardDirs::findExe(QString::fromLatin1("kdeinit_wrapper"))); + + if(rt) + proc << QFile::encodeName(KStandardDirs::findExe(QString::fromLatin1("artswrapper"))); + else + proc << QFile::encodeName(KStandardDirs::findExe(QString::fromLatin1("artsd"))); + + proc << QStringList::split( " ", config.readEntry( "Arguments", "-F 10 -S 4096 -s 60 -m artsmessage -l 3 -f" ) ); + + if(proc.start(KProcess::Block) && proc.normalExit()) + { + // We could have a race-condition here. + // The correct way to do it is to make artsd fork-and-exit + // after starting to listen to connections (and running artsd + // directly instead of using kdeinit), but this is better + // than nothing. + int time = 0; + do + { + sleep(1); + d->server = Arts::Reference("global:Arts_SoundServerV2"); + } while(++time < 5 && (d->server.isNull())); + + emit restartedServer(); + } + // TODO else what? + + return d->server; +} + +// vim: sw=4 ts=4 noet +#include "kartsserver.moc" diff --git a/arts/kde/kartsserver.h b/arts/kde/kartsserver.h new file mode 100644 index 000000000..8456e25ea --- /dev/null +++ b/arts/kde/kartsserver.h @@ -0,0 +1,75 @@ +// Copyright (c) 2000-2001 Charles Samuels <charles@kde.org> +// Neil Stevens <neil@qualityassistant.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIAB\ILITY, WHETHER IN +// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef KARTSSERVER_H +#define KARTSSERVER_H + +#include "kmedia2.h" +#include <qobject.h> +#include "soundserver.h" +#include <kdelibs_export.h> + +/** + * KArtsServer is a wrapper to conveniently get a reference to a SoundServer, + * and restart artsd when necessary, using the kcontrol settings. + * + * Of course we'd rather that artsd never crashed, and that all users start + * artsd on KDE startup, but at the very least there will always be third + * party PlayObjects that will crash. So, this is necessary. + */ +class KDE_ARTS_EXPORT KArtsServer : public QObject +{ +Q_OBJECT + +public: + /** + * Create a new KArtsServer. Don't forget to create a KArtsDispatcher + * before using KArtsServer. + */ + KArtsServer(QObject *parent = 0, const char *name = 0); + virtual ~KArtsServer(void); + + /** + * Get a verified reference to the SoundServerV2, (re)starting artsd + * using the kcontrol-specified settings if necessary. + * + * If the soundserver has changed since you called this method the last + * time (meaning artsd was restarted) restartedServer() will be emitted. + */ + Arts::SoundServerV2 server(void); + +signals: + /** + * This is emitted when the soundserver has been restarted (by this + * KArtsServer instance or outside). It is not + * emitted automatically when the soundserver comes up but only after + * your code calls server(). + */ + void restartedServer(void); + +private: + KArtsServer(const KArtsServer &rhs); + KArtsServer &operator=(const KArtsServer &rhs); + + struct Data; + Data *d; +}; + +#endif diff --git a/arts/kde/kaudioconverter.cc b/arts/kde/kaudioconverter.cc new file mode 100644 index 000000000..a5f1e8e43 --- /dev/null +++ b/arts/kde/kaudioconverter.cc @@ -0,0 +1,198 @@ + /* + + Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "config.h" +#include "artskde.h" +#include "connect.h" +#include "flowsystem.h" +#include "audiosubsys.h" +#include "dynamicrequest.h" +#include "kdatarequest_impl.h" +#include "kioinputstream_impl.h" +#include "kaudioconverter.moc" + +#include <iostream> + +#include <qfile.h> +#include <qtimer.h> + +#include <kurl.h> +#include <kdebug.h> +#include <kmimetype.h> +#include <kapplication.h> + +using namespace std; + +KAudioConverter::KAudioConverter() +{ + m_incoming = 0; + m_started = false; +} + +KAudioConverter::~KAudioConverter() +{ + delete m_incoming; +} + +bool KAudioConverter::setup(int samplingRate) +{ + string backupAudioIO = Arts::AudioSubSystem::the()->audioIO(); + int backupSamplingRate = Arts::AudioSubSystem::the()->samplingRate(); + + Arts::AudioSubSystem::the()->audioIO("null"); + Arts::AudioSubSystem::the()->samplingRate(samplingRate); + + if(!Arts::AudioSubSystem::the()->open()) + { + Arts::AudioSubSystem::the()->audioIO(backupAudioIO); + Arts::AudioSubSystem::the()->samplingRate(backupSamplingRate); + + return false; + } + + return true; +} + +void KAudioConverter::slotMimeType(const QString &mimeType) +{ + m_mimeType = mimeType; + kapp->exit_loop(); +} + +void KAudioConverter::requestPlayObject(const KURL &url) +{ + string queryInterface = "Arts::PlayObject"; + + Arts::KIOInputStream inputStream; + + if(!url.isLocalFile()) + { + Arts::KIOInputStream_impl *inputStreamImpl = new Arts::KIOInputStream_impl(); + inputStream = Arts::KIOInputStream::_from_base(inputStreamImpl); + + QObject::connect(inputStreamImpl, SIGNAL(mimeTypeFound(const QString &)), SLOT(slotMimeType(const QString &))); + + inputStream.openURL(url.url().latin1()); + inputStream.streamStart(); + + // ugly hacks.. :/ + kapp->enter_loop(); + + queryInterface = "Arts::StreamPlayObject"; + } + else + { + KMimeType::Ptr mimetype = KMimeType::findByURL(url); + m_mimeType = mimetype->name(); + } + + Arts::TraderQuery query; + query.supports("Interface", queryInterface); + query.supports("MimeType", string(m_mimeType.latin1())); + + string objectType; + + vector<Arts::TraderOffer> *offers = query.query(); + if(!offers->empty()) + objectType = offers->front().interfaceName(); // first offer + + delete offers; + + if(objectType.empty()) + { + m_incoming = 0; + return; + } + + if(!url.isLocalFile()) + { + Arts::StreamPlayObject result = Arts::SubClass(objectType); + result.streamMedia(inputStream); + result._node()->start(); + + m_incoming = new KPlayObject(result, true); + } + else + { + Arts::PlayObject result = Arts::SubClass(objectType); + + if(result.loadMedia(string(QFile::encodeName(url.path())))) + { + result._node()->start(); + m_incoming = new KPlayObject(result, false); + } + else + m_incoming = 0; + } +} + +void KAudioConverter::start() +{ + if(m_started || !m_incoming) + return; + + m_started = true; + + emit rawStreamStart(); + + m_incoming->play(); + + Arts::KDataRequest_impl *requestImpl = new Arts::KDataRequest_impl(); + m_request = Arts::KDataRequest::_from_base(requestImpl); + + Arts::connect(m_incoming->object(), "left", m_request, "left"); + Arts::connect(m_incoming->object(), "right", m_request, "right"); + + QObject::connect(requestImpl, SIGNAL(newBlockSize(long)), SIGNAL(newBlockSize(long))); + QObject::connect(requestImpl, SIGNAL(newBlockPointer(long)), SIGNAL(newBlockPointer(long))); + QObject::connect(requestImpl, SIGNAL(newData()), SIGNAL(newData())); + + // Special mpeglib case + // TODO: needed at all?? + usleep(100000); + if(m_incoming->object()._base()->_isCompatibleWith("DecoderBaseObject")) + if(!Arts::DynamicRequest(m_incoming->object()).method("_set_blocking").param(true).invoke()) + cerr << "mpeglib, and blocking attribute can't be changed?" << endl; + + m_request.start(); + + // TODO: Maybe do this async, using QTimer::singleShot + // But jowenn i think jowenn is right -> this would + // lead to problems in slotNewData() when accessing the data + // (could already be overwritten...) + while(m_incoming->state() != Arts::posIdle) + m_request.goOn(); + + stop(); +} + +void KAudioConverter::stop() +{ + if(!m_started || !m_incoming) + return; + + m_incoming->halt(); + m_request.streamEnd(); + + m_started = false; + + emit rawStreamFinished(); +} diff --git a/arts/kde/kaudioconverter.h b/arts/kde/kaudioconverter.h new file mode 100644 index 000000000..6235739d8 --- /dev/null +++ b/arts/kde/kaudioconverter.h @@ -0,0 +1,65 @@ + /* + + Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KAUDIOCONVERTER_H +#define KAUDIOCONVERTER_H + +#include <qobject.h> +#include "artskde.h" +#include "kplayobject.h" + +class KURL; +class QString; + +class KAudioConverter : public QObject +{ +Q_OBJECT +public: + KAudioConverter(); + ~KAudioConverter(); + + bool setup(int samplingRate); + void requestPlayObject(const KURL &url); + + void start(); + void stop(); + +signals: + void rawStreamStart(); + + void newBlockSize(long blockSize); + void newBlockPointer(long blockPointer); + void newData(); + + void rawStreamFinished(); + +private slots: + void slotMimeType(const QString &mimeType); + +private: + Arts::KDataRequest m_request; + KPlayObject *m_incoming; + QString m_mimeType; + + bool m_started; +}; + +#endif diff --git a/arts/kde/kaudiomanagerplay.cpp b/arts/kde/kaudiomanagerplay.cpp new file mode 100644 index 000000000..12b817a87 --- /dev/null +++ b/arts/kde/kaudiomanagerplay.cpp @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "kaudiomanagerplay.h" +#include "kartsserver.h" + +#include <soundserver.h> +#include <string> + +KAudioManagerPlay::KAudioManagerPlay( KArtsServer * server, const QString & title ) +{ + d = new PrivateData; + d->amanPlay = Arts::DynamicCast( server->server().createObject( "Arts::Synth_AMAN_PLAY" ) ); + d->started = false; + setTitle( title ); +} + +KAudioManagerPlay::~KAudioManagerPlay() +{ + stop(); + delete d; +} + +Arts::Synth_AMAN_PLAY KAudioManagerPlay::amanPlay() +{ + return d->amanPlay; +} + +bool KAudioManagerPlay::isNull() const +{ + if( !this ) + return true; + return d->amanPlay.isNull(); +} + +void KAudioManagerPlay::setTitle( const QString & title ) +{ + d->amanPlay.title( std::string( title.local8Bit() ) ); +} + +QString KAudioManagerPlay::title() +{ + return QString::fromLocal8Bit( d->amanPlay.title().c_str() ); +} + +void KAudioManagerPlay::setAutoRestoreID( const QString & autoRestoreID ) +{ + d->amanPlay.autoRestoreID( std::string( autoRestoreID.local8Bit() ) ); +} + +QString KAudioManagerPlay::autoRestoreID() +{ + return QString::fromLocal8Bit( d->amanPlay.autoRestoreID().c_str() ); +} + +void KAudioManagerPlay::start() +{ + if( d->started ) + return; + + d->started = true; + d->amanPlay.start(); +} + +void KAudioManagerPlay::stop() +{ + if( !d->started ) + return; + + d->started = false; + d->amanPlay.stop(); +} + +// vim: sw=4 ts=4 diff --git a/arts/kde/kaudiomanagerplay.h b/arts/kde/kaudiomanagerplay.h new file mode 100644 index 000000000..6bf332130 --- /dev/null +++ b/arts/kde/kaudiomanagerplay.h @@ -0,0 +1,84 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef KAUDIOMANAGERPLAY_H +#define KAUDIOMANAGERPLAY_H + +#include <artsflow.h> +#include <qstring.h> +#include <kdelibs_export.h> + +class KArtsServer; +class QString; + +/** + * KDE Wrapper for Arts::Synth_AMAN_PLAY. Use this class to create an entry in + * the AudioManager - that's the list you see when opening the AudioManager view + * in artscontrol. + * + * @author Matthias Kretz <kretz@kde.org> + * @since 3.2 + */ +class KDE_ARTS_EXPORT KAudioManagerPlay +{ + public: + KAudioManagerPlay( KArtsServer * server, const QString & title = QString::null ); + ~KAudioManagerPlay(); + + /** + * Returns the internal Arts::Synth_AMAN_PLAY + */ + Arts::Synth_AMAN_PLAY amanPlay(); + + /** + * return true if this == 0 or amanPlay().isNull() + * + * in essence, ((KDE::PlayObject*)0)->isNull() will not + * crash + **/ + bool isNull() const; + + /** + * Set the name of the output in the AudioManager + */ + void setTitle( const QString & title ); + + /** + * returns the name of the output as it appears in the AudioManager + */ + QString title(); + + void setAutoRestoreID( const QString & autoRestoreID ); + QString autoRestoreID(); + + void start(); + void stop(); + + private: + struct PrivateData { + Arts::Synth_AMAN_PLAY amanPlay; + bool started; + }; + PrivateData* d; +}; + + +#endif // KAUDIOMANAGERPLAY_H + +// vim: sw=4 ts=4 diff --git a/arts/kde/kaudioplaystream.cpp b/arts/kde/kaudioplaystream.cpp new file mode 100644 index 000000000..200128ffc --- /dev/null +++ b/arts/kde/kaudioplaystream.cpp @@ -0,0 +1,210 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "kaudioplaystream.h" +#include "kaudioplaystream_p.h" + +#include <kartsserver.h> +#include <kaudiomanagerplay.h> + +#include <artsflow.h> +#include <soundserver.h> + +#include <kglobal.h> +#include <kdebug.h> + +#include <qstring.h> +//#include <qptrqueue.h> +//#include <qcstring.h> //QByteArray + +#include <string.h> // for strncpy + +//#include <assert.h> + +KAudioPlayStreamPrivate::KAudioPlayStreamPrivate( KArtsServer* server, const QString title, QObject* p, const char* n ) + : QObject( p,n ) + , _server( server ) + , _play( new KAudioManagerPlay( _server, title ) ) + , _effectrack( Arts::StereoEffectStack::null() ) + , _polling( true ), _attached( false ), _effects( true ) +{ +kdDebug( 400 ) << k_funcinfo << endl; + initaRts(); +} + +KAudioPlayStreamPrivate::~KAudioPlayStreamPrivate() +{ + kdDebug( 400 ) << k_funcinfo << endl; + _play->stop(); + if ( _effects ) _effectrack.stop(); + _bs2a.stop(); +} + +void KAudioPlayStreamPrivate::initaRts() { + kdDebug( 400 ) << k_funcinfo << endl; + + _effectrack = Arts::DynamicCast( _server->server().createObject( "Arts::StereoEffectStack" ) ); + if ( _effectrack.isNull() ) + { + kdWarning( 400 ) << "Couldn't create EffectStack!" << endl; + _effects = false; + } + + _bs2a = Arts::DynamicCast( _server->server().createObject( "Arts::ByteStreamToAudio" ) ); + if ( _bs2a.isNull() ) + kdFatal( 400 ) << "Couldn't create ByteStreamToAudio" << endl; + + if ( _effects ) + { + Arts::connect( _effectrack, _play->amanPlay() ); + Arts::connect( _bs2a, _effectrack ); + } else { + Arts::connect( _bs2a, _play->amanPlay() ); + } + + _play->start(); + if ( _effects ) _effectrack.start(); +} + +KAudioPlayStream::KAudioPlayStream( KArtsServer* server, const QString title, QObject* p, const char* n ) + : QObject( p,n ) + , d( new KAudioPlayStreamPrivate( server, title, this ) ) +{ + kdDebug( 400 ) << k_funcinfo << endl; +} +KAudioPlayStream::~KAudioPlayStream() +{ + kdDebug( 400 ) << k_funcinfo << endl; +} + +void KAudioPlayStream::setPolling( bool n ) { d->_polling = n; } +bool KAudioPlayStream::polling() const { return d->_polling; } + +bool KAudioPlayStream::running() const { return d->_attached; } + +Arts::StereoEffectStack KAudioPlayStream::effectStack() const { + return d->_effectrack; +} + +void KAudioPlayStream::start( int samplingRate, int bits, int channels ) +{ + kdDebug( 400 ) << k_funcinfo << "samplingRate: " << samplingRate << " bits: " << bits << " channels: " << channels << endl; + if ( !d->_attached ) + { + d->_bs2a.samplingRate( samplingRate ); + d->_bs2a.channels( channels ); + d->_bs2a.bits( bits ); + + d->_sender = new KByteSoundProducer( this, d->_server->server().minStreamBufferTime(), samplingRate, bits, channels, "PS" ); + d->_artssender = Arts::ByteSoundProducerV2::_from_base( d->_sender ); + Arts::connect( d->_artssender, "outdata", d->_bs2a, "indata" ); + + d->_bs2a.start(); + d->_artssender.start(); + +// // Needed? + Arts::Dispatcher::the()->ioManager()->processOneEvent( false ); + + d->_attached = true; + emit running( d->_attached ); + } +} +void KAudioPlayStream::stop() +{ + kdDebug( 400 ) << k_funcinfo << endl; + if ( d->_attached ) + { + d->_attached = false; + + d->_bs2a.stop(); + d->_artssender.stop(); + + // Shortly stop the play so we dont get clicks and artefacts + d->_play->stop(); + d->_play->start(); + + Arts::disconnect( d->_artssender, d->_bs2a ); + d->_artssender = Arts::ByteSoundProducerV2::null(); + d->_sender = 0; + + emit running( d->_attached ); + } +} + +void KAudioPlayStream::write( QByteArray& ) +{ +} + +void KAudioPlayStream::fillData( Arts::DataPacket<Arts::mcopbyte> *packet ) +{ + //kdDebug( 400 ) << k_funcinfo << "packet->size=" << packet->size << endl; + if ( d->_polling ) + { + QByteArray bytearray( packet->size ); + bytearray.setRawData( ( char* )packet->contents, packet->size ); + bytearray.fill( 0 ); + emit requestData( bytearray ); + bytearray.resetRawData( ( char* )packet->contents, packet->size ); + + //for ( int i=0; i<10; i++ ) + // kdDebug() << packet->contents[ i ] << " : " << bytearray.data()[ i ] << endl; + } else { + /// TODO: Implement a queue and fetching from it... + } +} + +// * * * KByteSoundProducer * * * + +KByteSoundProducer::KByteSoundProducer( KAudioPlayStream* impl, float minBufferTime, int rate, int bits, int channels, const char * title ) + : _samplingRate( rate ) + , _channels( channels ) + , _bits( bits ) + , _packets( 7 ) + , _title( title ) + , _impl( impl ) +{ + // Calculate packet count (packetsize is fixed to packetCapacity = 4096 + float streamBufferTime; + do { + _packets++; + streamBufferTime = ( float )( _packets * packetCapacity * 1000 ) + / ( float )( _samplingRate * _channels * 2 ); + } while ( streamBufferTime < minBufferTime ); + //kdDebug( 400 ) << k_funcinfo << "_packets:" << _packets << " packetCapacity:" << packetCapacity << endl; +} + +KByteSoundProducer::~KByteSoundProducer() +{ +} + +void KByteSoundProducer::streamStart() { outdata.setPull( _packets, packetCapacity ); } +void KByteSoundProducer::streamEnd() { outdata.endPull(); } + +void KByteSoundProducer::request_outdata( Arts::DataPacket<Arts::mcopbyte> *packet ) +{ + if ( _impl->running() ) { + _impl->fillData( packet ); + packet->send(); + } +} + +// vim: sw=4 ts=4 tw=80 + +#include "kaudioplaystream.moc" +#include "kaudioplaystream_p.moc" diff --git a/arts/kde/kaudioplaystream.h b/arts/kde/kaudioplaystream.h new file mode 100644 index 000000000..8f34cc8c9 --- /dev/null +++ b/arts/kde/kaudioplaystream.h @@ -0,0 +1,127 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef KAUDIOPLAYSTREAM_H +#define KAUDIOPLAYSTREAM_H + +#include <qobject.h> + +#include <qcstring.h> +#include <stdsynthmodule.h> + +#include <kdelibs_export.h> + +class KArtsServer; +namespace Arts { class StereoEffectStack; } + +class KAudioPlayStreamPrivate; + +/** + * @brief A wrapper around ByteSoundProducer/ByteStreamToAudio/Synth_AMAN_PLAY. + * + * @author Arnold Krille <arnold@arnoldarts.de> + * @since 3.2 +*/ + +class KDE_ARTS_EXPORT KAudioPlayStream : public QObject { + Q_OBJECT +public: + /** + * Creates a KAudioPlayStream on server with a title. You should pass the KArtsServer also + * as parent to be sure this object is deleted before the server is. + * + * @param server The server where it should play to. + * @param title The title that is shown in the AudioManager. + * @param parent You will propably want to pass the server as parent to so this stream gets deleted before the server disappears. + * @param name The name of the stream. + */ + KAudioPlayStream( KArtsServer* server, const QString title, QObject* parent=0, const char* name=0 ); + /** + * Destructs the KAudioPlayStream. + */ + ~KAudioPlayStream(); + + /** + * Controls wether this Stream should poll the data from you via the signal requestData() + * or you use write() to fill the inputbuffer. + * + * Default is true + */ + void setPolling( bool ); + /** + * Returns the polling state. + * @see setPolling + */ + bool polling() const; + + /** + * @return wether this stream is running ("on air") or not. + */ + bool running() const; + + /** + * @return The Arts::StereoEffectStack right before the Synth_AMAN_PLAY. + */ + Arts::StereoEffectStack effectStack() const; +public slots: + /** + * Start the stream. + * @param samplingRate how many samples per second ( typically 11000/22050/44100/48000 ) + * @param bits how many bits per sample ( 8 / 16 ) + * @param channels how many channels ( 1 or 2 ) + */ + void start( int samplingRate, int bits, int channels ); + /** + * Stops the stream. + */ + void stop(); + + /** + * Write data into the inputbuffer. + * If you ignore the signal noData() it will play 0 ( silence ). + */ + void write( QByteArray& data ); +signals: + /** + * This signal is emitted when audio should be played. + * You have to fill the array with data. + */ + void requestData( QByteArray& ); + + /** + * Is emitted when the state changes. + */ + void running( bool ); + + /** + * Is emitted if the inputbuffer runs dry and polling os off. + */ + void noData(); +public: + /** + * @internal + */ + void fillData( Arts::DataPacket<Arts::mcopbyte> *packet ); +private: + KAudioPlayStreamPrivate* d; +}; + +#endif // KAUDIOPLAYSTREAM_H + +// vim: sw=4 ts=4 tw=80 diff --git a/arts/kde/kaudioplaystream_p.h b/arts/kde/kaudioplaystream_p.h new file mode 100644 index 000000000..a7e5cc4e7 --- /dev/null +++ b/arts/kde/kaudioplaystream_p.h @@ -0,0 +1,84 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef KAUDIOPLAYSTREAM_P_H +#define KAUDIOPLAYSTREAM_P_H + +#include <soundserver.h> +#include <stdsynthmodule.h> + +#include <qobject.h> + +class KArtsServer; +class KAudioManagerPlay; +namespace Arts { + class Synth_AMAN_PLAY; + class StereoEffectStack; + class ByteStreamToAudio; +} + +class KAudioPlayStream; +class KByteSoundProducer; + +class KAudioPlayStreamPrivate : public QObject { + Q_OBJECT +public: + KAudioPlayStreamPrivate( KArtsServer*, const QString title, QObject*, const char* =0 ); + ~KAudioPlayStreamPrivate(); + + KArtsServer* _server; + KAudioManagerPlay* _play; + Arts::StereoEffectStack _effectrack; + Arts::ByteStreamToAudio _bs2a; + KByteSoundProducer* _sender; + Arts::ByteSoundProducerV2 _artssender; + bool _polling, _attached, _effects; + +public slots: + void initaRts(); +}; + +class KByteSoundProducer : virtual public Arts::ByteSoundProducerV2_skel + , virtual public Arts::StdSynthModule +{ +public: + KByteSoundProducer( KAudioPlayStream*, float minBufferTime, int rate, int bits, int channels, const char * title ); + ~KByteSoundProducer(); + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + std::string title() { return _title; } + + void streamStart(); + void streamEnd(); + +protected: + void request_outdata( Arts::DataPacket<Arts::mcopbyte> *packet ); + +private: + long _samplingRate, _channels, _bits, _packets; + std::string _title; + enum { packetCapacity = 4096 }; + KAudioPlayStream* _impl; +}; + +#endif // KAUDIOPLAYSTREAM_P_H + +// vim: sw=4 ts=4 diff --git a/arts/kde/kaudiorecordstream.cpp b/arts/kde/kaudiorecordstream.cpp new file mode 100644 index 000000000..53788e296 --- /dev/null +++ b/arts/kde/kaudiorecordstream.cpp @@ -0,0 +1,269 @@ + /* + + Copyright (C) 2001, 2002 Matthias Kretz + kretz@kde.org + 2003 Arnold Krille + arnold@arnoldarts.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "kaudiorecordstream.h" +#include "kaudiorecordstream_p.h" +#include "kartsserver.h" + +#include <artsflow.h> +#include <soundserver.h> + +#include <kglobal.h> +#include <kdebug.h> + +#include <qstring.h> +#include <qptrqueue.h> +#include <qcstring.h> //QByteArray + +#include <assert.h> + +struct KAudioRecordStream::Data +{ + Arts::Synth_AMAN_RECORD in; + Arts::AudioToByteStream convert; + Arts::StereoEffectStack effectStack; + Arts::ByteSoundReceiver receiver; + KByteSoundReceiver * receiver_base; + KArtsServer * kserver; + bool attached; + bool blocking; + bool polling; + unsigned int pos; + QPtrQueue<QByteArray> inqueue; + QString title; +}; + +KAudioRecordStream::KAudioRecordStream( KArtsServer * kserver, const QString & title, QObject * parent, const char * name ) + : QObject( parent, name ) + , d( new Data ) +{ + d->kserver = kserver; + d->attached = false; + d->blocking = true; + d->polling = false; + d->pos = 0; + d->inqueue.setAutoDelete( true ); + d->title = title; + + connect( d->kserver, SIGNAL( restartedServer() ), SLOT( slotRestartedServer() ) ); + + d->in = Arts::DynamicCast( d->kserver->server().createObject( "Arts::Synth_AMAN_RECORD" ) ); + d->effectStack = Arts::DynamicCast( d->kserver->server().createObject( "Arts::StereoEffectStack" ) ); + d->convert = Arts::DynamicCast( d->kserver->server().createObject( "Arts::AudioToByteStream" ) ); + if( d->in.isNull() ) + kdFatal( 400 ) << "couldn't create a Synth_AMAN_RECORD on the aRts server\n"; + if( d->effectStack.isNull() ) + kdFatal( 400 ) << "couldn't create a StereoEffectStack on the aRts server\n"; + if( d->convert.isNull() ) + kdFatal( 400 ) << "couldn't create a AudioToByteStream on the aRts server\n"; + + d->in.title( ( const char * ) d->title.local8Bit() ); + Arts::connect( d->in, d->effectStack ); + d->in.start(); + d->effectStack.start(); +} + +KAudioRecordStream::~KAudioRecordStream() +{ + d->receiver = Arts::ByteSoundReceiver::null(); + // don't delete receiver_base because aRts takes care of that (in the line + // above) + d->receiver_base = 0; + delete d; +} + +int KAudioRecordStream::read( char * buffer, int size ) +{ + kdDebug( 400 ) << k_funcinfo << endl; + unsigned int remaining = size; + while( remaining ) + { + if( d->blocking ) + while( d->inqueue.isEmpty() ) + Arts::Dispatcher::the()->ioManager()->processOneEvent( true ); + else + { + if( d->inqueue.isEmpty() ) + Arts::Dispatcher::the()->ioManager()->processOneEvent( false ); + if( d->inqueue.isEmpty() ) + return size - remaining; + } + QByteArray * data = d->inqueue.head(); + unsigned int tocopy = kMin( remaining, data->size() - d->pos ); + memcpy( buffer, data->data() + d->pos, tocopy ); + d->pos += tocopy; + buffer += tocopy; + remaining -= tocopy; + if( d->pos == data->size() ) + { + d->inqueue.remove(); + d->pos = 0; + } + } + return size; +} + +void KAudioRecordStream::setBlockingIO( bool blocking ) +{ + d->blocking = blocking; +} + +bool KAudioRecordStream::blockingIO() const +{ + return d->blocking; +} + +void KAudioRecordStream::usePolling( bool polling ) +{ + d->polling = polling; + if( ! polling ) + flush(); +} + +bool KAudioRecordStream::polling() const +{ + return d->polling; +} + +Arts::StereoEffectStack KAudioRecordStream::effectStack() const +{ + return d->effectStack; +} + +bool KAudioRecordStream::running() const +{ + return d->attached; +} + +void KAudioRecordStream::stop() +{ + kdDebug( 400 ) << k_funcinfo << endl; + if( d->attached ) + { + d->receiver.stop(); + d->convert.stop(); + + Arts::disconnect( d->convert, d->receiver ); + d->receiver = Arts::ByteSoundReceiver::null(); + d->receiver_base = 0; + + Arts::disconnect( d->effectStack, d->convert ); + + d->attached = false; + emit running( false ); + } +} + +void KAudioRecordStream::start( int samplingRate, int bits, int channels ) +{ + kdDebug( 400 ) << k_funcinfo << "samplingRate: " << samplingRate << " bits: " << bits << " channels: " << channels << endl; + if( ! d->attached ) + { + assert( d->kserver ); + + if( ( samplingRate < 500 || samplingRate > 2000000 ) + || ( channels != 1 && channels != 2 ) || ( bits != 8 && bits != 16 ) ) + { + kdWarning( 400 ) << "invalid stream parameters: rate=" << samplingRate << ", " << bits << " bit, " << channels << " channels\n"; + } + else + { + d->convert.samplingRate( samplingRate ); + d->convert.channels( channels ); + d->convert.bits( bits ); + Arts::connect( d->effectStack, d->convert ); + + d->receiver_base = new KByteSoundReceiver( samplingRate, bits, channels, d->title.local8Bit() ); + d->receiver = Arts::ByteSoundReceiver::_from_base( d->receiver_base ); + connect( d->receiver_base, SIGNAL( data( const char *, unsigned int ) ), + SLOT( slotData( const char *, unsigned int ) ) ); + Arts::connect( d->convert, "outdata", d->receiver, "indata" ); + + d->convert.start(); + d->receiver.start(); + + //### needed? + Arts::Dispatcher::the()->ioManager()->processOneEvent( false ); + d->attached = true; + emit running( true ); + } + } +} + +void KAudioRecordStream::flush() +{ + kdDebug( 400 ) << k_funcinfo << endl; + d->inqueue.clear(); +} + +void KAudioRecordStream::slotRestartedServer() { } + +void KAudioRecordStream::slotData( const char * contents, unsigned int size ) +{ + //kdDebug( 400 ) << k_funcinfo << endl; + QByteArray * bytearray = new QByteArray( size ); + // copy the contents to the bytearray + // this has to be deleted later + bytearray->duplicate( contents, size ); + if( d->polling ) + { + kdDebug( 400 ) << "enqueue the data\n"; + d->inqueue.enqueue( bytearray ); + } + else + { + //kdDebug( 400 ) << "emit the data\n"; + emit data( *bytearray ); + //kdDebug( 400 ) << "delete the data\n"; + delete bytearray; + } +} + +//////////////////////////////////////// +// ---*--- KByteSoundReceiver ---*--- // +//////////////////////////////////////// + +KByteSoundReceiver::KByteSoundReceiver( int rate, int bits, int channels, const char * title ) + : _samplingRate( rate ) + , _bits( bits ) + , _channels( channels ) + , _title( title ) +{ +} + +KByteSoundReceiver::~KByteSoundReceiver() +{ +} + +void KByteSoundReceiver::process_indata( Arts::DataPacket<Arts::mcopbyte> * inpacket ) +{ + //kdDebug( 400 ) << k_funcinfo << " size of the packet: " << inpacket->size << endl; + emit data( (char *)inpacket->contents, inpacket->size ); + inpacket->processed(); +} + +// vim:sw=4:ts=4 + +#include "kaudiorecordstream.moc" +#include "kaudiorecordstream_p.moc" diff --git a/arts/kde/kaudiorecordstream.h b/arts/kde/kaudiorecordstream.h new file mode 100644 index 000000000..9f8097676 --- /dev/null +++ b/arts/kde/kaudiorecordstream.h @@ -0,0 +1,165 @@ + /* + + Copyright (C) 2001,2002 Matthias Kretz + kretz@kde.org + 2003 Arnold Krille + arnold@arnoldarts.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef _KAUDIORECORDSTREAM__H +#define _KAUDIORECORDSTREAM__H + +#include <qobject.h> + +#include <kdelibs_export.h> + +class KArtsServer; +namespace Arts { class StereoEffectStack; } + +/** + * @brief A KDE wrapper around Synth_AMAN_RECORD/AudioToByteStream/ByteSoundReceiver + * + * @author Matthias Kretz <kretz@kde.org> + * @since 3.2 +*/ +class KDE_ARTS_EXPORT KAudioRecordStream : public QObject +{ + Q_OBJECT + + public: + /** + * Construct a KAudioRecordStream + * + * @param server The server where it should record from. + * @param title The title that is shown in the AudioManager. + * @param parent You will propably want to pass the server as parent to so this stream gets deleted before the server disappears. + * @param name The name of the stream. + */ + KAudioRecordStream( KArtsServer * server, const QString & title, QObject * parent = 0, const char * name = 0 ); + + ~KAudioRecordStream(); + + /** + * You can read @p size number of bytes. If blockingIO() is set the method + * will return as soon as it has all your data and could possibly block your + * program. The method returns the number of bytes that are actually in the + * buffer. + * + * @see usePolling() + */ + int read( char *, int size ); + + /** + * If you set blockingIO to true the read method will wait + * until it has enough data to return exactly what you asked for. If + * blockingIO is false you can count on having control back to your + * program soon enough + */ + void setBlockingIO( bool ); + + /** + * read blocking I/O setting + * + * @see setBlockingIO() + */ + bool blockingIO() const; + + /** + * If you want to poll for data using read() set this to true. If + * you'd rather not poll use the data() signal for asynchronous + * I/O. If you set polling to true and don't call read() or + * flush() the inputbuffer will grow endlessly. + * + * The default is false (if you want to use read() set this to true). + */ + void usePolling( bool ); + + /** + * read whether polling is enabled + * + * @see usePolling() + */ + bool polling() const; + + /** + * @return The Effect Stack right after the Synth_AMAN_RECORD. + */ + Arts::StereoEffectStack effectStack() const; + + /** + * @return Wether it is running (recording) or not. + * @since 3.2 + */ + bool running() const; + + public slots: + /** + * Detaches the stream from the soundserver but doesn't remove the Synth_AMAN_RECORD + * so that the entry in the Audiomanager remains. + */ + void stop(); + + /** + * Attach to the soundserver and start getting data to read. This method + * must be called as soon as you want to receive data. In any case you have + * to call start() before read() + * + * @param samplingRate The sampling rate the stream should be resampled to. Use + * a number between 500 and 2000000. + * @param bits The number of bits the stream should have. Only 8 and + * 16 Bits are supported. + * @param channels The number of channels (mono/stereo). Only 1 and 2 are + * supported. + */ + void start( int samplingRate, int bits, int channels ); + + /** + * flush input buffer + */ + void flush(); + + signals: + /** + * Data from the aRts server has arrived. You should copy the data + * because the passed QByteArray will be deleted right after + * returning from your slot(s). + * + * @param data the data from the server + */ + void data( QByteArray & data ); + + /** + * Wether this RecordStream is recording or not. + * @since 3.2 + */ + void running( bool ); + + private slots: + void slotRestartedServer(); + void slotData( const char *, unsigned int ); + + private: + KAudioRecordStream( const KAudioRecordStream & ); + KAudioRecordStream & operator=( const KAudioRecordStream & ); + + struct Data; + Data * d; +}; + +#endif //_KAUDIORECORDSTREAM__H diff --git a/arts/kde/kaudiorecordstream_p.h b/arts/kde/kaudiorecordstream_p.h new file mode 100644 index 000000000..f2899519a --- /dev/null +++ b/arts/kde/kaudiorecordstream_p.h @@ -0,0 +1,62 @@ + /* + + Copyright (C) 2002 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef _KAUDIORECORDSTREAM_P__H +#define _KAUDIORECORDSTREAM_P__H + +#include <soundserver.h> +#include <stdsynthmodule.h> + +#include <qobject.h> + +class KByteSoundReceiver : public QObject, + public Arts::ByteSoundReceiver_skel, + public Arts::StdSynthModule +{ + Q_OBJECT + + public: + KByteSoundReceiver( int rate, int bits, int channels, const char * title ); + ~KByteSoundReceiver(); + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + std::string title() { return _title; } + + signals: + /** + * new data arrived, the data pointer will be deleted + * after this signal was emitted. So if you want to keep it + * you have to copy it. + */ + void data( const char * data, unsigned int size ); + + protected: + void process_indata(Arts::DataPacket<Arts::mcopbyte> *); + + private: + int _samplingRate, _bits, _channels; + std::string _title; +}; + +#endif // _KAUDIORECORDSTREAM_P__H diff --git a/arts/kde/kconverttest.cc b/arts/kde/kconverttest.cc new file mode 100644 index 000000000..25cb02e4c --- /dev/null +++ b/arts/kde/kconverttest.cc @@ -0,0 +1,96 @@ +#include <stdio.h> + +#include <qfile.h> +#include <qobject.h> + +#include <klocale.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kapplication.h> + +#include <flowsystem.h> +#include <kplayobject.h> +#include <kartsdispatcher.h> +#include <kplayobjectfactory.h> +#include <kaudioconverter.h> +#include "kconverttest.moc" + +using namespace std; +using namespace Arts; + +static KCmdLineOptions options[] = +{ + { "+[URL]", I18N_NOOP("URL to open"), 0 }, + KCmdLineLastOption +}; + +KConvertTest::KConvertTest() +{ +} + +void KConvertTest::slotRawStreamStart() +{ +// cout << "[START]\n\n" << endl; +} + +void KConvertTest::slotNewBlockSize(long blockSize) +{ + m_blockSize = blockSize; +} + +void KConvertTest::slotNewBlockPointer(long blockPointer) +{ + m_blockPointer = blockPointer; +} + +void KConvertTest::slotNewData() +{ + fwrite((void *) m_blockPointer, 1, m_blockSize, stdout); +} + +void KConvertTest::slotRawStreamFinished() +{ +// cout << "\n\n[END]" << endl; +} + +int main(int argc, char **argv) +{ + KAboutData aboutData("kconverttest", I18N_NOOP("KConvertTest"), I18N_NOOP("0.1"), "", KAboutData::License_GPL, ""); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KURL url; + + if(args->count()) + url = args->arg(0); + else + exit(1); + + args->clear(); + + KConvertTest *get = new KConvertTest(); + + KArtsDispatcher dispatcher; + KAudioConverter converter; + + // FIXME: crashes + // converter.setup(44100); + converter.requestPlayObject(url); + + QObject::connect(&converter, SIGNAL(rawStreamStart()), get, SLOT(slotRawStreamStart())); + + QObject::connect(&converter, SIGNAL(newBlockSize(long)), get, SLOT(slotNewBlockSize(long))); + QObject::connect(&converter, SIGNAL(newBlockPointer(long)), get, SLOT(slotNewBlockPointer(long))); + QObject::connect(&converter, SIGNAL(newData()), get, SLOT(slotNewData())); + + QObject::connect(&converter, SIGNAL(rawStreamFinished()), get, SLOT(slotRawStreamFinished())); + + converter.start(); + + app.exec(); +} + diff --git a/arts/kde/kconverttest.h b/arts/kde/kconverttest.h new file mode 100644 index 000000000..60847b0aa --- /dev/null +++ b/arts/kde/kconverttest.h @@ -0,0 +1,46 @@ + /* + + Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KCONVERTTEST_H +#define KCONVERTTEST_H + +#include <qobject.h> + +class KConvertTest : public QObject +{ +Q_OBJECT +public: + KConvertTest(); + +public slots: + void slotRawStreamStart(); + + void slotNewBlockSize(long blockSize); + void slotNewBlockPointer(long blockPointer); + void slotNewData(); + + void slotRawStreamFinished(); + +private: + long m_blockSize, m_blockPointer; +}; + +#endif diff --git a/arts/kde/kdatarequest_impl.cpp b/arts/kde/kdatarequest_impl.cpp new file mode 100644 index 000000000..ce8f30f9b --- /dev/null +++ b/arts/kde/kdatarequest_impl.cpp @@ -0,0 +1,80 @@ + /* + + Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include <kdebug.h> +#include "flowsystem.h" +#include "convert.h" +#include "kdatarequest_impl.moc" + +using namespace Arts; + +KDataRequest_impl::KDataRequest_impl() +{ + m_lastBlockSize = 0; + m_outBlock = 0; +} + +KDataRequest_impl::~KDataRequest_impl() +{ + delete []m_outBlock; +} + +void KDataRequest_impl::streamInit() +{ +} + +void KDataRequest_impl::streamEnd() +{ +} + +void KDataRequest_impl::calculateBlock(unsigned long samples) +{ + long blockSize = samples * 4; + + if(m_lastBlockSize != blockSize) + { + delete []m_outBlock; + emit newBlockSize(blockSize); + + m_outBlock = new unsigned char[blockSize]; // 2 channels, 16 bit + + emit newBlockPointer((long) m_outBlock); + + m_lastBlockSize = blockSize; + } + + convert_stereo_2float_i16le(samples, left, right, m_outBlock); + emit newData(); +} + +/* + * this is the most tricky part here - since we will run in a context + * where no audio hardware will play the "give me more data role", + * we'll have to request things ourselves (requireFlow() tells the + * flowsystem that more signal flow should happen, so that + * calculateBlock will get called + */ +void KDataRequest_impl::goOn() +{ + _node()->requireFlow(); +} + +REGISTER_IMPLEMENTATION(KDataRequest_impl); diff --git a/arts/kde/kdatarequest_impl.h b/arts/kde/kdatarequest_impl.h new file mode 100644 index 000000000..07522f0f1 --- /dev/null +++ b/arts/kde/kdatarequest_impl.h @@ -0,0 +1,59 @@ + /* + + Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KDATAREQUEST_IMPL +#define KDATAREQUEST_IMPL + +#include <qobject.h> +#include "artskde.h" +#include "stdsynthmodule.h" + +namespace Arts +{ + +class KDataRequest_impl : public QObject, virtual public KDataRequest_skel, + virtual public StdSynthModule +{ +Q_OBJECT +public: + KDataRequest_impl(); + ~KDataRequest_impl(); + + void streamInit(); + void streamEnd(); + + void calculateBlock(unsigned long samples); + + void goOn(); + +signals: + void newData(); + void newBlockSize(long blockSize); + void newBlockPointer(long blockPointer); + +private: + long m_lastBlockSize; + unsigned char *m_outBlock; +}; + +} + +#endif diff --git a/arts/kde/kioinputstream_impl.cpp b/arts/kde/kioinputstream_impl.cpp new file mode 100644 index 000000000..b82764931 --- /dev/null +++ b/arts/kde/kioinputstream_impl.cpp @@ -0,0 +1,236 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +/* + * How does it work? + * ----------------- + * + * First the buffer has to be filled. When it reaches a defined size the outdata + * stream has to start pulling packets. If the buffer reaches a size of zero the + * stream has to stop. If the buffer gets to big the job has to be suspended + * until the buffer is small enough again. + */ + +#include <kapplication.h> +#include <kdebug.h> +#include <kio/job.h> +#include <kio/kmimetype.h> +#include <kio/jobclasses.h> +#include <qtimer.h> +#include <qdatastream.h> +#include "artsversion.h" +#include "kioinputstream_impl.moc" + +using namespace Arts; + +const unsigned int KIOInputStream_impl::PACKET_COUNT = 10; + +KIOInputStream_impl::KIOInputStream_impl() : m_packetSize(2048) +{ + m_job = 0; + m_finished = false; + m_firstBuffer = false; + m_packetBuffer = 16; + m_streamStarted = false; + m_streamSuspended = false; + m_streamPulled = false; + m_size = 0; +} + +KIOInputStream_impl::~KIOInputStream_impl() +{ + if(m_job != 0) + m_job->kill(); +} + +void KIOInputStream_impl::streamStart() +{ + // prevent kill/reconnect + if (m_streamStarted) { + kdDebug( 400 ) << "not restarting stream!\n"; + if (m_job->isSuspended()) + m_job->resume(); + return; + } + + kdDebug( 400 ) << "(re)starting stream\n"; + + if(m_job != 0) + m_job->kill(); + m_job = KIO::get(m_url, false, false); + + m_job->addMetaData("accept", "audio/x-mp3, video/mpeg, application/ogg"); + m_job->addMetaData("UserAgent", QString::fromLatin1("aRts/") + QString::fromLatin1(ARTS_VERSION)); + + QObject::connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), + this, SLOT(slotData(KIO::Job *, const QByteArray &))); + QObject::connect(m_job, SIGNAL(result(KIO::Job *)), + this, SLOT(slotResult(KIO::Job *))); + QObject::connect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)), + this, SLOT(slotScanMimeType(KIO::Job *, const QString &))); + QObject::connect(m_job, SIGNAL(totalSize( KIO::Job *, KIO::filesize_t)), + this, SLOT(slotTotalSize(KIO::Job *, KIO::filesize_t))); + + m_streamStarted = true; +} + +void KIOInputStream_impl::streamEnd() +{ + kdDebug( 400 ) << "streamEnd()\n"; + + if(m_job != 0) + { + QObject::disconnect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), + this, SLOT(slotData(KIO::Job *, const QByteArray &))); + QObject::disconnect(m_job, SIGNAL(result(KIO::Job *)), + this, SLOT(slotResult(KIO::Job *))); + QObject::disconnect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)), + this, SLOT(slotScanMimeType(KIO::Job *, const QString &))); + QObject::disconnect(m_job, SIGNAL(totalSize( KIO::Job *, KIO::filesize_t)), + this, SLOT(slotTotalSize(KIO::Job *, KIO::filesize_t))); + + if ( m_streamPulled ) + outdata.endPull(); + + m_job->kill(); + m_job = 0; + } + + m_streamStarted = false; +} + +bool KIOInputStream_impl::openURL(const std::string& url) +{ + m_url = KURL(url.c_str()); + m_size = 0; + return true; +} + +void KIOInputStream_impl::slotData(KIO::Job *, const QByteArray &data) +{ + if(m_finished) + m_finished = false; + + QDataStream dataStream(m_data, IO_WriteOnly | IO_Append); + dataStream.writeRawBytes(data.data(), data.size()); + //kdDebug( 400 ) << "STREAMING: buffersize = " << m_data.size() << " bytes" << endl; + + processQueue(); +} + +void KIOInputStream_impl::slotResult(KIO::Job *job) +{ + // jobs delete themselves after emitting their result + m_finished = true; + m_streamStarted = false; + m_job = 0; + + if(job->error()) { + // break out of the event loop in case of + // connection error + emit mimeTypeFound("application/x-zerosize"); + job->showErrorDialog(); + } +} + +void KIOInputStream_impl::slotScanMimeType(KIO::Job *, const QString &mimetype) +{ + kdDebug( 400 ) << "got mimetype: " << mimetype << endl; + emit mimeTypeFound(mimetype); +} + +void KIOInputStream_impl::slotTotalSize(KIO::Job *, KIO::filesize_t size) +{ + m_size = size; +} + +bool KIOInputStream_impl::eof() +{ + return (m_finished && m_data.size() == 0); +} + +bool KIOInputStream_impl::seekOk() +{ + return false; +} + +long KIOInputStream_impl::size() +{ + return m_size ? m_size : m_data.size(); +} + +long KIOInputStream_impl::seek(long) +{ + return -1; +} + +void KIOInputStream_impl::processQueue() +{ + if(m_job != 0) + { + if(m_data.size() > (m_packetBuffer * m_packetSize * 2) && !m_job->isSuspended()) + { + kdDebug( 400 ) << "STREAMING: suspend job" << endl; + m_job->suspend(); + } + else if(m_data.size() < (m_packetBuffer * m_packetSize) && m_job->isSuspended()) + { + kdDebug( 400 ) << "STREAMING: resume job" << endl; + m_job->resume(); + } + } + + if (!m_firstBuffer) { + if(m_data.size() < (m_packetBuffer * m_packetSize * 2) ) { + kdDebug( 400 ) << "STREAMING: Buffering in progress... (Needed bytes before it starts to play: " << ((m_packetBuffer * m_packetSize * 2) - m_data.size()) << ")" << endl; + return; + } else { + m_firstBuffer = true; + m_streamPulled = true; + outdata.setPull(PACKET_COUNT, m_packetSize); + } + } +} + +void KIOInputStream_impl::request_outdata(DataPacket<mcopbyte> *packet) +{ + processQueue(); + packet->size = std::min(m_packetSize, m_data.size()); + kdDebug( 400 ) << "STREAMING: Filling one DataPacket with " << packet->size << " bytes of the stream!" << endl; + + if (!m_finished) { + if( (unsigned)packet->size < m_packetSize || ! m_firstBuffer) { + m_firstBuffer = false; + packet->size = 0; + outdata.endPull(); + } + } + + if (packet->size > 0) + { + memcpy(packet->contents, m_data.data(), packet->size); + memmove(m_data.data(), m_data.data() + packet->size, m_data.size() - packet->size); + m_data.resize(m_data.size() - packet->size); + } + packet->send(); +} + +REGISTER_IMPLEMENTATION(KIOInputStream_impl); diff --git a/arts/kde/kioinputstream_impl.h b/arts/kde/kioinputstream_impl.h new file mode 100644 index 000000000..95daac169 --- /dev/null +++ b/arts/kde/kioinputstream_impl.h @@ -0,0 +1,89 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KIOINPUTSTREAM_IMPL +#define KIOINPUTSTREAM_IMPL + +#include <qobject.h> +#include <qcstring.h> +#include <kio/jobclasses.h> +#include <kurl.h> +#include "artskde.h" +#include "stdsynthmodule.h" + +namespace Arts { + +class KIOInputStream_impl : public QObject, virtual public KIOInputStream_skel, + virtual public InputStream_skel, + virtual public StdSynthModule +{ +Q_OBJECT +public: + KIOInputStream_impl(); + ~KIOInputStream_impl(); + + void streamStart(); + void streamEnd(); + + bool eof(); + bool seekOk(); + long size(); + long seek(long); + + bool openURL(const std::string& url); + + void processQueue(); + void request_outdata(DataPacket<mcopbyte> *packet); + + long bufferPackets() { return m_packetBuffer; } + void bufferPackets(long i) { m_packetBuffer = i; } + + long packetSize() { return m_packetSize; } + +signals: + void mimeTypeFound(const QString & mimetype); + +private slots: + void slotData(KIO::Job *, const QByteArray &); + void slotResult(KIO::Job *); + void slotScanMimeType(KIO::Job *, const QString &mimetype); + void slotTotalSize(KIO::Job *, KIO::filesize_t size); + +private: + KURL m_url; + KIO::TransferJob *m_job; + QByteArray m_data; + bool m_finished; + bool m_firstBuffer; + bool m_streamStarted; + bool m_streamSuspended; + bool m_streamPulled; + + unsigned int m_packetBuffer; + const unsigned int m_packetSize; + KIO::filesize_t m_size; + + static const unsigned int PACKET_COUNT; +}; + +} + +#endif diff --git a/arts/kde/kiotest.cc b/arts/kde/kiotest.cc new file mode 100644 index 000000000..b5403ce0d --- /dev/null +++ b/arts/kde/kiotest.cc @@ -0,0 +1,54 @@ +#include <stdio.h> +#include <kmedia2.h> +#include <kcmdlineargs.h> +#include <connect.h> +#include <klocale.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include "qiomanager.h" +#include "artskde.h" + +using namespace std; +using namespace Arts; + + +static KCmdLineOptions options[] = +{ + { "+[URL]", I18N_NOOP("URL to open"), 0 }, + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KAboutData aboutData( "kiotest", I18N_NOOP("KIOTest"), I18N_NOOP("0.1"), "", KAboutData::License_GPL, ""); + + KCmdLineArgs::init(argc,argv,&aboutData); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + QIOManager qiomanager; + Dispatcher dispatcher(&qiomanager); + KIOInputStream stream; + StdoutWriter writer; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if(args->count()) + { + if(!stream.openURL(args->arg(0))) + { + printf("can't open url"); + exit(1); + } + } + else + exit(1); + + args->clear(); + + connect(stream, writer); + + writer.start(); + stream.start(); + + app.exec(); +} diff --git a/arts/kde/kiotestslow.cc b/arts/kde/kiotestslow.cc new file mode 100644 index 000000000..fd5f1e129 --- /dev/null +++ b/arts/kde/kiotestslow.cc @@ -0,0 +1,131 @@ +#include <stdio.h> +#include <kmedia2.h> +#include <kcmdlineargs.h> +#include <connect.h> +#include <klocale.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <stdsynthmodule.h> +#include "qiomanager.h" +#include "artskde.h" + +using namespace std; +using namespace Arts; + +namespace Arts { +/* simulate slow receiver */ +class KIOTestSlow_impl : public KIOTestSlow_skel, + public TimeNotify, + public StdSynthModule +{ + int pos; + list< DataPacket<mcopbyte>* > q; + InputStream _inputStream; + +public: + InputStream inputStream() { return _inputStream; } + void inputStream(InputStream i) { _inputStream = i; } + + KIOTestSlow_impl() + { + Dispatcher::the()->ioManager()->addTimer(10, this); + pos = 0; + } + void notifyTime() + { + if(!_inputStream.isNull() && _inputStream.eof()) + { + printf("\n[*EOF*] remaining = %d packets\n"); + _inputStream = InputStream::null(); + return; + } + + int TODO = 100; + do { + if(q.empty()) + return; + + DataPacket<mcopbyte> *p = q.front(); + char ch = p->contents[pos++]; + if(p->size == pos) + { + p->processed(); + q.pop_front(); + pos = 0; + } + + if(ch == '\n') + { + long size = 0; + list<DataPacket<mcopbyte>*>::iterator i; + for(i = q.begin(); i != q.end(); i++) + size += (*i)->size; + printf("\n[queued %8ld] ",size-pos); + } + else + putchar(ch); + + } while(TODO-- > 0); + } + void process_data(DataPacket<mcopbyte> *p) + { + if(p->size == 0) + p->processed(); + else + q.push_back(p); + } +}; +REGISTER_IMPLEMENTATION(KIOTestSlow_impl); +}; + +static KCmdLineOptions options[] = +{ + { "+[URL]", I18N_NOOP("URL to open"), 0 }, + KCmdLineLastOption +}; + +#undef USE_FILEINPUTSTREAM + +int main(int argc, char **argv) +{ + KAboutData aboutData( "kiotestslow", I18N_NOOP("KIOTest"), I18N_NOOP("0.1"), "", KAboutData::License_GPL, ""); + + KCmdLineArgs::init(argc,argv,&aboutData); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + QIOManager qiomanager; + Dispatcher dispatcher(&qiomanager); +#ifndef USE_FILEINPUTSTREAM + KIOInputStream stream; +#else + FileInputStream stream; +#endif + KIOTestSlow writer; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if(args->count()) + { +#ifdef USE_FILEINPUTSTREAM + if(!stream.open(args->arg(0))) +#else + if(!stream.openURL(args->arg(0))) +#endif + { + printf("can't open url"); + exit(1); + } + } + else + exit(1); + + args->clear(); + + writer.inputStream(stream); + connect(stream, writer); + + writer.start(); + stream.start(); + + app.exec(); +} diff --git a/arts/kde/kplayobject.cc b/arts/kde/kplayobject.cc new file mode 100644 index 000000000..af37735cb --- /dev/null +++ b/arts/kde/kplayobject.cc @@ -0,0 +1,303 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include "kplayobject.h" +#include "kplayobject.moc" +#include "kplayobjectcreator.h" +#include <kdebug.h> + +KPlayObject::KPlayObject() : QObject() +{ + m_playObject = Arts::PlayObject::null(); + m_isStream = false; +} + +KPlayObject::KPlayObject(Arts::PlayObject playobject, bool isStream) : QObject() +{ + m_playObject = playobject; + m_isStream = isStream; +} + +KPlayObject::~KPlayObject() +{ +} + +void KPlayObject::play() +{ + object().play(); +} + +void KPlayObject::seek(Arts::poTime newTime) +{ + if(!m_isStream) + object().seek(newTime); + else + kdDebug( 400 ) << "Seeking in a Stream? huh?" << endl; +} + +void KPlayObject::pause() +{ + object().pause(); +} + +void KPlayObject::halt() +{ + object().halt(); +} + +QString KPlayObject::description() +{ + return QString::fromLatin1(object().description().c_str()); +} + +Arts::poTime KPlayObject::currentTime() +{ + return object().currentTime(); +} + +Arts::poTime KPlayObject::overallTime() +{ + return object().overallTime(); +} + +Arts::poCapabilities KPlayObject::capabilities() +{ + return object().capabilities(); +} + +QString KPlayObject::mediaName() +{ + return QString::fromLatin1(object().mediaName().c_str()); +} + +Arts::poState KPlayObject::state() +{ + return object().state(); +} + +Arts::PlayObject KPlayObject::object() +{ + return m_playObject; +} + +bool KPlayObject::isNull() +{ + if( !this ) + return true; + return object().isNull(); +} + +void KPlayObject::setObject(Arts::PlayObject playObject) +{ + m_playObject = playObject; +} + +bool KPlayObject::stream() +{ + return m_isStream; +} + +struct KDE::PlayObject::PrivateData +{ + PrivateData() : creator( 0 ), + isProxy( false ), + internalState( Arts::posIdle ) {} + ~PrivateData() { + delete creator; + } + Arts::SoundServerV2 server; + KDE::PlayObjectCreator* creator; + bool createBUS; + bool isProxy; + Arts::poState internalState; + KURL url; +}; + +KDE::PlayObject::PlayObject() : QObject() +{ + m_playObject = Arts::PlayObject::null(); + m_isStream = false; + d = new PrivateData; +} + +KDE::PlayObject::PlayObject(Arts::PlayObject playobject, bool isStream) : QObject() +{ + m_playObject = playobject; + m_isStream = isStream; + d = new PrivateData; + + //very funny! you can't connect to signals before creating + //the object - so nobody will ever receive this signal (mkretz) + // + //emit playObjectCreated(); +} + +KDE::PlayObject::PlayObject( Arts::SoundServerV2 server, const KURL& url, bool isStream, bool createBUS ) : QObject() +{ + kdDebug( 400 ) << "KDE::PlayObject: created as proxy for URL " << url.url()<< endl; + + m_playObject = Arts::PlayObject::null(); + m_isStream = isStream; + d = new PrivateData; + d->server = server; + d->url = url; + d->createBUS = createBUS; + d->isProxy = true; +} + +KDE::PlayObject::~PlayObject() +{ + kdDebug( 400 ) << "KDE::PlayObject: destroyed" << endl; + + delete d; +} + +void KDE::PlayObject::play() +{ + kdDebug( 400 ) << "KDE::PlayObject::play()" << endl; + + if ( object().isNull() ) { + if ( m_isStream ) { + if ( d->creator ) + delete d->creator; + d->creator = new KDE::PlayObjectCreator( d->server ); + d->creator->create( d->url, d->createBUS, this, SLOT( attachPlayObject( Arts::PlayObject ) ) ); + kdDebug( 400 ) << "KDE::PlayObject::play(): creator called" << endl; + d->internalState = Arts::posPlaying; + } + return; + } + object().play(); +} + +void KDE::PlayObject::attachPlayObject( Arts::PlayObject playObject ) +{ + kdDebug( 400 ) << "KDE::PlayObject::attachPlayObject()" << endl; + + m_playObject = playObject; + emit playObjectCreated(); + if ( object().isNull() ) + return; + switch ( d->internalState ) { + case Arts::posIdle: + object().halt(); + break; + case Arts::posPaused: + object().pause(); + break; + case Arts::posPlaying: + object().play (); + break; + } +} + +void KDE::PlayObject::seek(Arts::poTime newTime) +{ + if ( object().isNull() ) + return; + if(!m_isStream) + object().seek(newTime); + else + kdDebug( 400 ) << "Seeking in a Stream? huh?" << endl; +} + +void KDE::PlayObject::pause() +{ + if ( !object().isNull() ) + object().pause(); + d->internalState = Arts::posPaused; +} + +void KDE::PlayObject::halt() +{ + kdDebug( 400 ) << "KDE::PlayObject::halt()" << endl; + if ( !object().isNull() ) + object().halt(); + else if ( d->creator ) { + delete d->creator; + d->creator = 0; + kdDebug( 400 ) << "KDE::PlayObject::halt(): creator destroyed" << endl; + } + d->internalState = Arts::posIdle; +} + +QString KDE::PlayObject::description() +{ + if ( object().isNull() ) + return QString(); + return QString::fromLatin1(object().description().c_str()); +} + +Arts::poTime KDE::PlayObject::currentTime() +{ + if ( object().isNull() ) + return Arts::poTime( 0, 0, -1, "" ); + return object().currentTime(); +} + +Arts::poTime KDE::PlayObject::overallTime() +{ + if ( object().isNull() ) + return Arts::poTime( 0, 0, -1, "" ); + return object().overallTime(); +} + +Arts::poCapabilities KDE::PlayObject::capabilities() +{ + if ( object().isNull() ) + return static_cast<Arts::poCapabilities>( 0 ); + return object().capabilities(); +} + +QString KDE::PlayObject::mediaName() +{ + if ( object().isNull() ) + return QString(); + return QString::fromLatin1(object().mediaName().c_str()); +} + +Arts::poState KDE::PlayObject::state() +{ + if ( object().isNull() ) + return d->internalState; + return object().state(); +} + +Arts::PlayObject KDE::PlayObject::object() +{ + return m_playObject; +} + +bool KDE::PlayObject::isNull() +{ + if ( !this ) + return true; + if ( d->isProxy ) + return false; + return object().isNull(); +} + +bool KDE::PlayObject::stream() +{ + return m_isStream; +} + +// vim: sw=4 ts=4 noet diff --git a/arts/kde/kplayobject.h b/arts/kde/kplayobject.h new file mode 100644 index 000000000..959e46810 --- /dev/null +++ b/arts/kde/kplayobject.h @@ -0,0 +1,306 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KPLAYOBJECT_H +#define KPLAYOBJECT_H + +#include "kmedia2.h" +#include "soundserver.h" +#include <kurl.h> +#include <qobject.h> + +class KDE_EXPORT KPlayObject : public QObject +{ +Q_OBJECT +public: + KPlayObject(); + KPlayObject(Arts::PlayObject playobject, bool isStream); + ~KPlayObject(); + + /** + * Sets the internal Arts::PlayObject + * to @a playObject + */ + void setObject(Arts::PlayObject playObject); + + /** + * Returns the internal Arts::PlayObject + */ + Arts::PlayObject object(); + + /** + * return true if both this != 0, and object.isNull() + * + * in essence, ((KPlayObject*)0)->isNull() will not + * crash + **/ + bool isNull(); + + /** + * returns true if the internally playobject + * is used to play a stream + */ + bool stream(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + void play(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + void seek(Arts::poTime newTime); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + void pause(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + + void halt(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + QString description(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + Arts::poTime currentTime(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + Arts::poTime overallTime(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + Arts::poCapabilities capabilities(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + QString mediaName(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + Arts::poState state(); + +private: + Arts::PlayObject m_playObject; + bool m_isStream; +}; + + + +namespace KDE { + +class PlayObjectFactory; + +/** + * This class acts as a general interface to the KDE multimedia framework. + * You basically point the Playobject to an URL and say "play", and it will + * automatically decode and play and / or display the file or stream. + * For non-local media, it will make extensive use of KIOInputStream to + * directly play the content from the remote location without having to + * download it to a temporary local file first. + * + * A KDE::PlayObject is never created directly with new, but only through + * a KDE::PlayObjectFactory. + * + * Basically, it is used like this: + * \code + * KArtsDispatcher dispatcher; + * KArtsServer server; + * KDE::PlayObjectFactory factory( server.server() ); + * KDE::PlayObject* playobj = factory.createPlayObject( someURL, true ); + * playobj->play(); + * \endcode + * + * Internally, the KDE::PlayObject acts as a wrapper for an Arts::PlayObject. + * + * Special care needs to be taken for non-local media. In general, you + * cannot safely figure out the mimetype of the remote media content, by + * looking at the URL alone. You need to download some data to analyze + * the content. Since KDE::PlayObject is only a wrapper for an + * Arts::PlayObject, and an Arts::PlayObject needs to know the mimetype + * of the data it plays in order to pick the correct decoder, one cannot + * directly create an Arts::PlayObject and attach it to a stream. Therefore, + * the following approach is used. + * + * Whenever a the factory creates a KDE::PlayObject for a non-local content, + * it first generates a so called "Proxy" Playobject. This is a + * KDE::PlayObject that does not contain a real Arts::PlayObject yet. + * As soon as you invoke the play() method, a connection to the media + * source is made, and as soon as the mimetype is known, the appropriate + * Arts::PlayObject is created. + * + * This has some side effects that developers need to be aware of: + * Until the real Arts::PlayObject got created, + * - the capabilities() method returns "zero" capabilities, + * - description() and mediaName() will return a null QString, + * - currentTime() and overallTime() will return "zero", + * - despite the fact that isNull() returns "false", object().isNull() + * will return "true". If you need to directly access methods of the + * internal Arts::PlayObject, be sure to use object().isNull() to guard + * your access. + * + * A KDE::PlayObject will emit the signal playObjectCreated() + * as soon as the real internal Arts::PlayObject got created. This is also + * true for local media files. So you can generally connect to this signal + * and act on it if your application needs to know about the real capabilities + * of the Arts::PlayObject. + * + * However, KDE::PlayObject will try to act reasonable on calls to play(), + * halt(), pause() and state(). If you call play() and then pause() + * before the connection to the media source was established, it will + * not start playing once the connection got established. Calling halt() + * will cancel the connection process. KDE::PlayObject will maintain + * an internal state variable, and calling state() will return this + * internal state until the real Arts::PlayObject got created, afterwards + * the state of the Arts::PlayObject will be returned. + */ +class KDE_EXPORT PlayObject : public QObject +{ +Q_OBJECT +public: + ~PlayObject(); + + /** + * Returns the internal Arts::PlayObject + */ + Arts::PlayObject object(); + + /** + * return true if this != 0. + * + * in essence, ((KDE::PlayObject*)0)->isNull() will not + * crash + **/ + bool isNull(); + + /** + * returns "true" if the content to play is delivered as a stream. + */ + bool stream(); + + /** + * causes the PlayObject to start the play back. + */ + void play(); + + /** + * causes the PlayObject to skip to the time @p newTime. + * You don't need to stop or restart the play back after calling seek. + */ + void seek(Arts::poTime newTime); + + /** + * causes the PlayObject to pause play back immediately. It will not + * restart until you call play(). This also works on streams, the + * connection to the media source will be maintained while the + * PlayObject is paused. + */ + void pause(); + + /** + * immediately stops the play back and resets the media to the + * start of the content. If playing from a stream, halt() causes + * the connection to be canceled. + */ + + void halt(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + QString description(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + Arts::poTime currentTime(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + Arts::poTime overallTime(); + + /** + * returns the capabilities of the PlayObject. The return value is + * a binary OR of Arts::capSeek and Arts::capPause, or 0. + */ + Arts::poCapabilities capabilities(); + + /** + * Reimplemented (Arts::PlayObject Wrapper) + */ + QString mediaName(); + + /** + * returns the internal state of the PlayObject. The state can be + * either Arts::posIdle, Arts::posPaused or Arts::posPlaying. A + * PlayObject in state Arts::posIdle is stopped. Once you call + * play(), the state changes to Arts::posPlaying. pause() causes + * the PlayObject to change to Arts::posPaused. + */ + Arts::poState state(); + +signals: + /** + * this signal is emitted as soon as the internal Arts::PlayObject + * is created and ready to play. It is granted that the Arts::PlayObject + * has not started playing, but KDE::PlayObject will call + * object().play() immediately after emitting this signal, so you + * need not do it yourself. + */ + void playObjectCreated(); + +private slots: + void attachPlayObject( Arts::PlayObject ); + +private: + Arts::PlayObject m_playObject; + bool m_isStream; + + struct PrivateData; + PrivateData* d; + + /* private constructors, to prevent instantiation and copying */ + PlayObject(); + PlayObject( const PlayObject& ) : QObject() {}; + PlayObject(Arts::PlayObject playobject, bool isStream); + PlayObject( Arts::SoundServerV2 server, const KURL& url, bool isStream, bool createBUS ); + + friend class KDE::PlayObjectFactory; + +}; + +} + +#endif diff --git a/arts/kde/kplayobjectcreator.cc b/arts/kde/kplayobjectcreator.cc new file mode 100644 index 000000000..26b4308ab --- /dev/null +++ b/arts/kde/kplayobjectcreator.cc @@ -0,0 +1,104 @@ + /* + + Copyright (C) 2002 Matthias Welwarsky <mwelwarsky@web.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include <kio/kmimetype.h> +#include "artskde.h" +#include "kplayobjectcreator.h" +#include "kplayobjectcreator.moc" +#include "kioinputstream_impl.h" + +#include <qfile.h> + +#include <kdebug.h> + +KDE::PlayObjectCreator::PlayObjectCreator(Arts::SoundServerV2 server) +{ + m_server = server; +} + +KDE::PlayObjectCreator::~PlayObjectCreator() +{ +} + +bool KDE::PlayObjectCreator::create(const KURL& url, bool createBUS, const QObject* receiver, const char* slot) +{ + // no need to go any further, and I hate deep indentation + if (m_server.isNull() || url.isEmpty() ) + return false; + + connect( this, SIGNAL( playObjectCreated( Arts::PlayObject ) ), + receiver, slot ); + + // check if the URL is a local file + if (!url.isLocalFile()) + { + m_createBUS = createBUS; + + // This is the RightWay(tm) according to stw + Arts::KIOInputStream_impl* instream_impl = new Arts::KIOInputStream_impl(); + m_instream = Arts::KIOInputStream::_from_base(instream_impl); + + // signal will be called once the ioslave knows the mime-type of the stream + connect(instream_impl, SIGNAL(mimeTypeFound(const QString &)), + this, SLOT(slotMimeType(const QString &))); + + // GO! + m_instream.openURL(url.url().latin1()); + m_instream.streamStart(); + + return true; + } + kdDebug( 400 ) << "stream is local file: " << url.url() << endl; + + // usual stuff if we have a local file + KMimeType::Ptr mimetype = KMimeType::findByURL(url); + emit playObjectCreated ( + m_server.createPlayObjectForURL(std::string(QFile::encodeName(url.path())), + std::string(mimetype->name().latin1()), + createBUS) + ); + return true; +} + +void KDE::PlayObjectCreator::slotMimeType(const QString& mimetype) +{ + + kdDebug( 400 ) << "slotMimeType called: " << mimetype << endl; + + QString mimetype_copy = mimetype; + + if ( mimetype_copy == "application/octet-stream" ) + mimetype_copy = QString("audio/x-mp3"); + + if (mimetype_copy == "application/x-zerosize") + emit playObjectCreated(Arts::PlayObject::null()); + + playObject = m_server.createPlayObjectForStream( + m_instream, + std::string( mimetype_copy.latin1() ), + m_createBUS ); + if ( playObject.isNull() ) { + m_instream.streamEnd(); + emit playObjectCreated( Arts::PlayObject::null() ); + return; + } + emit playObjectCreated( playObject ); +} diff --git a/arts/kde/kplayobjectcreator.h b/arts/kde/kplayobjectcreator.h new file mode 100644 index 000000000..31b0a0b48 --- /dev/null +++ b/arts/kde/kplayobjectcreator.h @@ -0,0 +1,56 @@ + /* + + Copyright (C) 2002 Matthias Welwarsky <mwelwarsky@web.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KPLAYOBJECTCREATOR_H +#define KPLAYOBJECTCREATOR_H + +#include <kurl.h> +#include <qobject.h> +#include "soundserver.h" +#include "kioinputstream_impl.h" + +namespace KDE { + +class PlayObjectCreator : public QObject +{ +Q_OBJECT +public: + PlayObjectCreator(Arts::SoundServerV2 server); + ~PlayObjectCreator(); + + bool create(const KURL& url, bool createBUS, const QObject* receiver, const char* slot); + +signals: + void playObjectCreated(Arts::PlayObject playObject); + +private slots: + void slotMimeType(const QString &mimetype); + +private: + Arts::SoundServerV2 m_server; + Arts::KIOInputStream m_instream; + Arts::PlayObject playObject; + bool m_createBUS; +}; + +} +#endif + diff --git a/arts/kde/kplayobjectfactory.cc b/arts/kde/kplayobjectfactory.cc new file mode 100644 index 000000000..ea0218746 --- /dev/null +++ b/arts/kde/kplayobjectfactory.cc @@ -0,0 +1,258 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include <kio/kmimetype.h> +#include "kplayobject.h" +#include "artskde.h" +#include "kplayobjectfactory.h" +#include "kplayobjectfactory_p.h" +#include "kplayobjectcreator.h" +#include "kioinputstream_impl.h" +#include "kartsdispatcher.h" +#include "kartsserver.h" + +#include <qfile.h> +#include <kdebug.h> +#include "kaudiomanagerplay.h" +#include <flowsystem.h> +#include <kio/netaccess.h> + +using namespace std; + +KPlayObjectFactory::KPlayObjectFactory(Arts::SoundServerV2 server) +{ + m_server = server; + m_allowStreaming = true; + m_stream = false; +} + +KPlayObjectFactory::KPlayObjectFactory(KArtsServer* server) +{ + m_server = server->server(); + m_allowStreaming = true; + m_stream = false; +} + +KPlayObjectFactory::~KPlayObjectFactory() +{ +} + +KPlayObject *KPlayObjectFactory::createPlayObject(const KURL& url, bool createBUS) +{ + KMimeType::Ptr mimetype = KMimeType::findByURL(url); + return createPlayObject(url, mimetype->name(), createBUS); +} + + +KPlayObject *KPlayObjectFactory::createPlayObject(const KURL& _url, const QString &mimetype, bool createBUS) +{ + // WHY DOES BROKEN KIO_MEDIA GIVE WRONG URLS? + // I hate it + // I hate it + // It sucks + // kio_media please die + KURL url = KIO::NetAccess::mostLocalURL(_url, 0); + + if(!m_server.isNull()) + { + if(mimetype == "application/octet-stream" && m_allowStreaming) + { + Arts::KIOInputStream instream; + instream.openURL(url.url().latin1()); + + m_stream = true; + + // TODO: what else than hardcoding audio/x-mp3 ? + return new KPlayObject(m_server.createPlayObjectForStream(instream, string("audio/x-mp3"), createBUS), true); + } + else + return new KPlayObject(m_server.createPlayObjectForURL(string(QFile::encodeName(url.path())), string(mimetype.latin1()), createBUS), false); + } + else + return new KPlayObject(); +} + + + +// + +KDE::PlayObjectFactory::PlayObjectFactory(Arts::SoundServerV2 server) +{ + d = new PrivateData; + d->server = server; + d->amanPlay = 0; + d->helper = 0; + d->allowStreaming = true; + d->isStream = false; +} + +KDE::PlayObjectFactory::PlayObjectFactory(KArtsServer* server) +{ + d = new PrivateData; + d->server = server->server(); + d->amanPlay = 0; + d->helper = 0; + d->allowStreaming = true; + d->isStream = false; +} + +KDE::PlayObjectFactory::~PlayObjectFactory() +{ + delete d->helper; + delete d; +} + +void KDE::PlayObjectFactory::setAudioManagerPlay( KAudioManagerPlay * amanPlay ) +{ + d->amanPlay = amanPlay; + if( ! d->helper ) + d->helper = new POFHelper; +} + +KDE::PlayObject *KDE::PlayObjectFactory::createPlayObject(const KURL& url, bool createBUS) +{ + KMimeType::Ptr mimetype = KMimeType::findByURL(url); + return createPlayObject(url, mimetype->name(), createBUS); +} + +KDE::PlayObject *KDE::PlayObjectFactory::createPlayObject(const KURL& _url, const QString &mimetype, bool createBUS) +{ + // WHY DOES BROKEN KIO_MEDIA GIVE WRONG URLS? + // I hate it + // I hate it + // It sucks + // kio_media please die + KURL url = KIO::NetAccess::mostLocalURL(_url, 0); + + // return a NULL playobject if the server is NULL + if ( d->server.isNull() || url.isEmpty() ) + return new KDE::PlayObject(); + + // if the program wants to use it's own Synth_AMAN_PLAY we don't need a + // bus + if( d->amanPlay && createBUS ) + { + kdWarning( 400 ) << "KDE::PlayObjectFactory was instructed to use a Synth_AMAN_PLAY for output but the program also asked for a Synth_BUS_UPLINK" << endl; + createBUS = false; + } + + // decide if it's a local file. mpeglib provides cdda reading and decoding, so we prefer that over kio_audiocd + if ( url.isLocalFile() || !d->allowStreaming || (url.protocol() == "audiocd" && mimetype == "application/x-cda" && mimeTypes().contains( "application/x-cda" ) ) ) + { + // we rely on the delivered mimetype if it's a local file + d->playObj = new KDE::PlayObject( d->server.createPlayObjectForURL( string( QFile::encodeName( url.path() ) ), string( mimetype.latin1() ), createBUS ), false ); + } + else + { + // if non-local, let the KPlayObject figure out the mimetype itself + // this invokes asynchronous creation automatically + d->playObj = new KDE::PlayObject( d->server, url, true, createBUS ); + } + + if( d->playObj->isNull() ) + { + delete d->playObj; + d->playObj = 0; + return new KDE::PlayObject(); // return a NULL playobject + } + + if( d->amanPlay ) + { + d->helper->po = d->playObj; + d->helper->ap = d->amanPlay; + if( d->playObj->object().isNull() && d->amanPlay ) + QObject::connect( d->playObj, SIGNAL( playObjectCreated() ), d->helper, SLOT( connectAmanPlay() ) ); + else + d->helper->connectAmanPlay(); + } + + return d->playObj; +} + +QStringList KDE::PlayObjectFactory::mimeTypes(void) +{ + KArtsDispatcher dispatcher; // we need such a thing, otherwise we crash + Arts::TraderQuery query; + vector<Arts::TraderOffer> *offers = query.query(); + + QStringList results; + for(vector<Arts::TraderOffer>::iterator offer = offers->begin(); + offer != offers->end(); ++offer) + { + vector<string> *mimetypes = (*offer).getProperty("MimeType"); + + for(vector<string>::iterator mimetype = mimetypes->begin(); + mimetype != mimetypes->end(); ++mimetype) + { + QString name = QString::fromLocal8Bit((*mimetype).c_str()).stripWhiteSpace(); + if(KMimeType::mimeType(name)) + results.append(name); + } + + delete mimetypes; + } + delete offers; + + // clean out duplicates + results.sort(); + for(QStringList::iterator result = results.begin(); result != results.end(); ) + { + QStringList::iterator previous = result; + ++result; + if(result != results.end() && *result == *previous) + { + results.remove(result); + result = previous; + } + } + + return results; +} + +/* ### KDE4 +void KDE::PlayObjectFactory::connectAmanPlay() +{ + kdDebug( 400 ) << k_funcinfo << endl; + if( d->playObj->object().isNull() ) + return; + + d->amanPlay->start(); + d->playObj->object()._node()->start(); + Arts::connect( d->playObj->object(), "left" , d->amanPlay->amanPlay(), "left" ); + Arts::connect( d->playObj->object(), "right", d->amanPlay->amanPlay(), "right" ); +} +*/ + +void KDE::POFHelper::connectAmanPlay() +{ + kdDebug( 400 ) << k_funcinfo << endl; + if( po->object().isNull() ) + return; + + ap->start(); + po->object()._node()->start(); + Arts::connect( po->object(), "left" , ap->amanPlay(), "left" ); + Arts::connect( po->object(), "right", ap->amanPlay(), "right" ); +} + +#include "kplayobjectfactory_p.moc" + +// vim: sw=4 ts=4 noet diff --git a/arts/kde/kplayobjectfactory.h b/arts/kde/kplayobjectfactory.h new file mode 100644 index 000000000..2f9c096fc --- /dev/null +++ b/arts/kde/kplayobjectfactory.h @@ -0,0 +1,156 @@ + /* + + Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifndef KPLAYOBJECTFACTORY_H +#define KPLAYOBJECTFACTORY_H + +#include <kurl.h> +#include <kdelibs_export.h> + +#include "soundserver.h" +#include "kplayobject.h" + +class KArtsServer; + +class KDE_EXPORT KPlayObjectFactory +{ +public: + /** + * Constructs a new Factory for creating aRts playobjects on the + * soundserver. + */ + KPlayObjectFactory(Arts::SoundServerV2 server); + + /** + * Convenience constructor to pass a KArtsServer instead of an + * Arts::SoundServerV2. This equivalent to calling + * KPlayObjectFactory( server.server() ). + * + * @since 3.2 + */ + KPlayObjectFactory(KArtsServer* server); + + ~KPlayObjectFactory(); + + KPlayObject *createPlayObject(const KURL& url, bool createBUS); + KPlayObject *createPlayObject(const KURL& url, const QString &mimetype, bool createBUS); + + void setAllowStreaming(bool s) { m_allowStreaming = s; } + bool allowStreaming() { return m_allowStreaming; } + + bool isAStream() { return m_stream; } + +private: + Arts::SoundServerV2 m_server; + bool m_allowStreaming; + bool m_stream; +}; + +class KAudioManagerPlay; + +namespace KDE { + +class POFHelper; + + /** + * This class implements a factory to create KDE::PlayObjects for + * a given URL and mimetype. A detailed description about how to + * use the KDE multimedia framework can be found in the documentation + * for KDE::PlayObject. + */ +class KDE_EXPORT PlayObjectFactory// : public QObject ### for KDE4 make it a QObject to be able to receive signals +{ +public: + /** + * Creates a KDE::PlayObjectFactory. @p server is an + * Arts::SoundServerV2 + */ + PlayObjectFactory(Arts::SoundServerV2 server); + /** + * Convenience constructor to pass a KArtsServer instead of an + * Arts::SoundServerV2. This equivalent to calling + * KDE::PlayObjectFactory( server.server() ). + * + * @since 3.2 + */ + PlayObjectFactory( KArtsServer* server ); + ~PlayObjectFactory(); + + /** + * If this is set the PlayObject doesn't create a Synth_BUS_UPLINK at all + * but always uses the Synth_AMAN_PLAY that you passed. + */ + void setAudioManagerPlay( KAudioManagerPlay * amanplay ); + + /** + * Creates a KDE::PlayObject to play back the file or stream + * @p url points to. Set @p createBUS to "true", if you want the + * PlayObject to be connected to a SYNTH_BUS_UPLINK on creation. + * This is usually the case. You only need to set this to "false" + * if you want to attach your own sound effects to the PlayObject. + * + * You don't need to know the mimetype of the file or stream, it + * will be detected automatically. + */ + KDE::PlayObject *createPlayObject(const KURL& url, bool createBUS); + + /** + * This method also creates a KDE::PlayObject, but does no automatic + * mimetype detection. Use this method with care. + */ + KDE::PlayObject *createPlayObject(const KURL& url, const QString &mimetype, bool createBUS); + + /** + * setAllowStreaming( true ) allows the factory to create a + * streaming PlayObject for a non-local URL. This is also the default. + * Usually, you should not need to set this to false. + */ + void setAllowStreaming(bool s) { d->allowStreaming = s; } + + /** + * returns "true" if the factory is allowed to create streaming + * PlayObjects. + */ + bool allowStreaming() { return d->allowStreaming; } + + /** + * Return the mimetypes that are playable + */ + static QStringList mimeTypes(void); + +/*private slots: ### KDE4 and remove Helper class + void connectAmanPlay();*/ + +private: + struct PrivateData { + Arts::SoundServerV2 server; + KDE::PlayObject* playObj; + KAudioManagerPlay* amanPlay; + POFHelper* helper; + bool allowStreaming; + bool isStream; + }; + PrivateData* d; +}; + +} +#endif +// vim: sw=4 ts=4 noet diff --git a/arts/kde/kplayobjectfactory_p.h b/arts/kde/kplayobjectfactory_p.h new file mode 100644 index 000000000..21ea4c4e9 --- /dev/null +++ b/arts/kde/kplayobjectfactory_p.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef KPLAYOBJECTFACTORY_P_H +#define KPLAYOBJECTFACTORY_P_H + +#include <qobject.h> +#include "kplayobjectfactory.h" + +namespace KDE +{ + +/** + * @internal + */ +class POFHelper : public QObject +{ + friend class PlayObjectFactory; + Q_OBJECT +private slots: + void connectAmanPlay(); +private: + KDE::PlayObject *po; + KAudioManagerPlay *ap; +}; + +} + +#endif // KPLAYOBJECTFACTORY_P_H +// vim: sw=4 ts=4 noet diff --git a/arts/kde/kvideowidget.cpp b/arts/kde/kvideowidget.cpp new file mode 100644 index 000000000..2b0fbd66b --- /dev/null +++ b/arts/kde/kvideowidget.cpp @@ -0,0 +1,446 @@ +/* + This file is part of KDE/aRts (Noatun) - xine integration + Copyright (C) 2002 Ewald Snel <ewald@rambo.its.tudelft.nl> + Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2 as published by the Free Software Foundation. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <time.h> +#ifdef HAVE_USLEEP +#include <unistd.h> +#endif +#include <qaccel.h> +#include <qcursor.h> + +#if defined Q_WS_X11 && ! defined K_WS_QTONLY +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#else +#define XEvent void +#endif + +#include <kaction.h> +#include <klocale.h> +#include "kvideowidget.h" + + +class KFullscreenVideoWidget : public KVideoWidget +{ +public: + KFullscreenVideoWidget( KVideoWidget *parent = 0, const char *name = 0 ); + +protected: + virtual void windowActivationChange( bool ); + virtual bool x11Event( XEvent *event ); + +private: + KVideoWidget *videoWidget; +}; + +KFullscreenVideoWidget::KFullscreenVideoWidget( KVideoWidget *parent, const char *name ) + : KVideoWidget( 0, name ) +{ + this->videoWidget = parent; + setEraseColor( black ); + setCursor(QCursor(Qt::BlankCursor)); +} + +void KFullscreenVideoWidget::windowActivationChange( bool ) +{ + if (!isActiveWindow()) + { + videoWidget->setWindowed(); + } +} + +bool KFullscreenVideoWidget::x11Event( XEvent *event ) +{ +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + if (event->type == ClientMessage && + event->xclient.message_type == + XInternAtom( qt_xdisplay(), "VPO_RESIZE_NOTIFY", False )) + { + videoWidget->resizeNotify( event->xclient.data.l[0], event->xclient.data.l[1] ); + } +#endif + return false; +} + +KVideoWidget::KVideoWidget( KXMLGUIClient *clientParent, QWidget *parent, const char *name, WFlags f ) + : KXMLGUIClient( clientParent ), + QWidget( parent, name, f ) +{ + init(); + // ??? + QString toolbarName = i18n("Video Toolbar"); + setXML(QString("<!DOCTYPE kpartgui>\n<kpartgui name=\"kvideowidget\" version=\"1\"><MenuBar><Menu name=\"edit\"><Separator/><Action name=\"double_size\"/><Action name=\"normal_size\"/><Action name=\"half_size\"/><Separator/><Action name=\"fullscreen_mode\"/></Menu></MenuBar><Toolbar name=\"VideoToolbar\"><text>Video Toolbar</text><Action name=\"fullscreen_mode\"/></Toolbar></kpartgui>"), true); +} + +KVideoWidget::KVideoWidget( QWidget *parent, const char *name, WFlags f ) + : QWidget( parent, name, f ) +{ + init(); +} + +void KVideoWidget::init(void) +{ + setMinimumSize(0, 0); + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + setFocusPolicy( ClickFocus ); + + fullscreenWidget = 0; + poVideo = Arts::VideoPlayObject::null(); + videoWidth = 0; + videoHeight = 0; + + // Setup actions + new KToggleAction( i18n("Fullscreen &Mode"), "window_fullscreen", + CTRL+SHIFT+Key_F, this, SLOT(fullscreenActivated()), + actionCollection(), "fullscreen_mode" ); + new KRadioAction( i18n("&Half Size"), ALT+Key_0, + this, SLOT(halfSizeActivated()), + actionCollection(), "half_size" ); + new KRadioAction( i18n("&Normal Size"), ALT+Key_1, + this, SLOT(normalSizeActivated()), + actionCollection(), "normal_size" ); + new KRadioAction( i18n("&Double Size"), ALT+Key_2, + this, SLOT(doubleSizeActivated()), + actionCollection(), "double_size" ); + + ((KToggleAction *)action( "half_size" ))->setExclusiveGroup( "KVideoWidget::zoom" ); + ((KToggleAction *)action( "normal_size" ))->setExclusiveGroup( "KVideoWidget::zoom" ); + ((KToggleAction *)action( "double_size" ))->setExclusiveGroup( "KVideoWidget::zoom" ); + + action("double_size")->setEnabled(false); + action("half_size")->setEnabled(false); + action("normal_size")->setEnabled(false); + action("fullscreen_mode")->setEnabled(false); +} + +KVideoWidget::~KVideoWidget() +{ + if (isEmbedded()) + { + poVideo.x11WindowId( -1 ); + poVideo = Arts::VideoPlayObject::null(); + } + + delete fullscreenWidget; +} + +void KVideoWidget::embed( Arts::VideoPlayObject vpo ) +{ + bool enable; + if (vpo.isNull()) + { + if (isEmbedded()) + { + poVideo.x11WindowId( -1 ); + poVideo = Arts::VideoPlayObject::null(); + } + + setBackgroundMode( PaletteBackground ); + repaint(); + + // Resize GUI + videoWidth = 0; + videoHeight = 0; + + if (isHalfSize() || isNormalSize() || isDoubleSize()) + emit adaptSize( 0, 0 ); + + enable = false; + updateGeometry(); + } + else + { + if (isEmbedded()) + { + poVideo.x11WindowId( -1 ); + } + + poVideo = vpo; + + // Don't reset fullscreen mode for video playlists + if (fullscreenWidget) + { + poVideo.x11WindowId( fullscreenWidget->winId() ); + fullscreenWidget->setBackgroundMode( NoBackground ); + + setEraseColor( black ); + } + else + { + poVideo.x11WindowId( winId() ); + setBackgroundMode( NoBackground ); + } + enable = true; + } + action("double_size")->setEnabled(enable); + action("half_size")->setEnabled(enable); + action("normal_size")->setEnabled(enable); + action("fullscreen_mode")->setEnabled(enable); +} + +QImage KVideoWidget::snapshot( Arts::VideoPlayObject vpo ) +{ +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + Window root; + Pixmap pixmap; + XImage *xImage; + unsigned int width, height, border, depth; + int x, y; + + if (vpo.isNull() || (long)(pixmap = vpo.x11Snapshot()) == -1) + return QImage(); + + // Get 32bit RGBA image data (stored in 1bpp pixmap) + XGetGeometry( qt_xdisplay(), pixmap, &root, &x, &y, &width, &height, &border, &depth ); + + xImage = XGetImage( qt_xdisplay(), pixmap, 0, 0, width, height, 1, XYPixmap ); + + if (xImage == 0) + { + XFreePixmap( qt_xdisplay(), pixmap ); + return QImage(); + } + + // Convert 32bit RGBA image data into Qt image + QImage qImage = QImage( (uchar *)xImage->data, width/32, height, 32, (QRgb *)0, 0, QImage::IgnoreEndian ).copy(); + + // Free X11 resources and return Qt image + XDestroyImage( xImage ); + XFreePixmap( qt_xdisplay(), pixmap ); + + return qImage; +#else + return 0; +#endif +} + +bool KVideoWidget::isEmbedded() +{ + return !poVideo.isNull(); +} + +bool KVideoWidget::isFullscreen() +{ + return ((KToggleAction *)action( "fullscreen_mode" ))->isChecked(); +} + +bool KVideoWidget::isHalfSize() +{ + return ((KToggleAction *)action( "half_size" ))->isChecked(); +} + +bool KVideoWidget::isNormalSize() +{ + return ((KToggleAction *)action( "normal_size" ))->isChecked(); +} + +bool KVideoWidget::isDoubleSize() +{ + return ((KToggleAction *)action( "double_size" ))->isChecked(); +} + +void KVideoWidget::setFullscreen() +{ + if (!isFullscreen()) + { + ((KToggleAction *)action( "fullscreen_mode" ))->setChecked( true ); + fullscreenActivated(); + } +} + +void KVideoWidget::setWindowed() +{ + if (isFullscreen()) + { + ((KToggleAction *)action( "fullscreen_mode" ))->setChecked( false ); + fullscreenActivated(); + } +} + +void KVideoWidget::setHalfSize() +{ + ((KToggleAction *)action( "half_size" ))->setChecked( true ); + halfSizeActivated(); +} + +void KVideoWidget::setNormalSize() +{ + ((KToggleAction *)action( "normal_size" ))->setChecked( true ); + normalSizeActivated(); +} + +void KVideoWidget::setDoubleSize() +{ + ((KToggleAction *)action( "double_size" ))->setChecked( true ); + doubleSizeActivated(); +} + +QSize KVideoWidget::sizeHint() const +{ + return QSize( videoWidth, videoHeight ); +} + +int KVideoWidget::heightForWidth( int w ) const +{ + if(videoWidth == 0) + return 0; + else + return int( double(w)*double(videoHeight)/double(videoWidth) ); +} + +void KVideoWidget::mousePressEvent( QMouseEvent *event ) +{ + QPoint pos = mapToGlobal( event->pos() ); + + emit mouseButtonPressed( event->button(), pos, event->state() ); + + // ### Remove in KDE4 + if ( event->button() == RightButton ) + emit rightButtonPressed( pos ); +} + +void KVideoWidget::mouseDoubleClickEvent( QMouseEvent *event ) +{ + emit mouseButtonDoubleClick( mapToGlobal( event->pos() ), event->state() ); +} + +void KVideoWidget::resizeEvent( QResizeEvent *event ) +{ + QWidget::resizeEvent( event ); + + if (width() > minimumWidth() || height() > minimumHeight()) + { + if (width() == QMAX( (videoWidth / 2), minimumWidth() ) && + height() == QMAX( (videoHeight / 2), minimumHeight() )) + ((KToggleAction *)action( "half_size" ))->setChecked( true ); + else if (width() == QMAX( videoWidth, minimumWidth() ) && + height() == QMAX( videoHeight, minimumHeight() )) + ((KToggleAction *)action( "normal_size" ))->setChecked( true ); + else if (width() == QMAX( (2 * videoWidth), minimumWidth() ) && + height() == QMAX( (2 * videoHeight), minimumHeight() )) + ((KToggleAction *)action( "double_size" ))->setChecked( true ); + else + { + ((KToggleAction *)action( "half_size" ))->setChecked( false ); + ((KToggleAction *)action( "normal_size" ))->setChecked( false ); + ((KToggleAction *)action( "double_size" ))->setChecked( false ); + } + } +} + +void KVideoWidget::resizeNotify( int width, int height ) +{ + if(!isEmbedded()) return; + + videoWidth = width; + videoHeight = height; + + if (isHalfSize()) + emit adaptSize( (videoWidth / 2), (videoHeight / 2) ); + else if (isNormalSize()) + emit adaptSize( videoWidth, videoHeight ); + else if (isDoubleSize()) + emit adaptSize( (2 * videoWidth), (2 * videoHeight) ); + + updateGeometry(); +} + +bool KVideoWidget::x11Event( XEvent *event ) +{ +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + if (event->type == ClientMessage && + event->xclient.message_type == + XInternAtom( qt_xdisplay(), "VPO_RESIZE_NOTIFY", False )) + { + resizeNotify( event->xclient.data.l[0], event->xclient.data.l[1] ); + } +#endif + return false; +} + +void KVideoWidget::fullscreenActivated() +{ + if (isFullscreen() == (fullscreenWidget != 0)) + return; + + if (isFullscreen()) + { + fullscreenWidget = new KFullscreenVideoWidget( this ); + + // Interconnect mouse button signals + connect( fullscreenWidget, SIGNAL(mouseButtonPressed( int, const QPoint &, int )), + this, SIGNAL(mouseButtonPressed( int, const QPoint &, int)) ); + + connect( fullscreenWidget, SIGNAL(mouseButtonDoubleClick( const QPoint &, int )), + this, SIGNAL(mouseButtonDoubleClick( const QPoint &, int )) ); + + // ### Remove in KDE4 + connect( fullscreenWidget, SIGNAL(rightButtonPressed(const QPoint &)), + this, SIGNAL(rightButtonPressed(const QPoint &)) ); + + // Leave fullscreen mode with <Escape> key + QAccel *a = new QAccel( fullscreenWidget ); + a->connectItem( a->insertItem( Key_Escape ), + this, SLOT(setWindowed()) ); + + fullscreenWidget->setFocus(); + fullscreenWidget->showFullScreen(); + + if (isEmbedded()) + { + poVideo.x11WindowId( fullscreenWidget->winId() ); + fullscreenWidget->setBackgroundMode( NoBackground ); + } + } + else + { + if (isEmbedded()) + { + poVideo.x11WindowId( winId() ); + setBackgroundMode( NoBackground ); + } + + delete fullscreenWidget; + fullscreenWidget = 0; + } +} + +void KVideoWidget::halfSizeActivated() +{ + if (isHalfSize()) + { + if(isEmbedded()) emit adaptSize( (videoWidth / 2), (videoHeight / 2) ); + setWindowed(); + } +} + +void KVideoWidget::normalSizeActivated() +{ + if (isNormalSize()) + { + if(isEmbedded()) emit adaptSize( videoWidth, videoHeight ); + setWindowed(); + } +} + +void KVideoWidget::doubleSizeActivated() +{ + if (isDoubleSize()) + { + if(isEmbedded()) emit adaptSize( (2 * videoWidth), (2 * videoHeight) ); + setWindowed(); + } +} + +#include "kvideowidget.moc" diff --git a/arts/kde/kvideowidget.h b/arts/kde/kvideowidget.h new file mode 100644 index 000000000..f314267ca --- /dev/null +++ b/arts/kde/kvideowidget.h @@ -0,0 +1,82 @@ +/* + This file is part of KDE/aRts (Noatun) - xine integration + Copyright (C) 2002 Ewald Snel <ewald@rambo.its.tudelft.nl> + Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2 as published by the Free Software Foundation. +*/ + +#ifndef ARTSKDE_KVIDEOWIDGET_H +#define ARTSKDE_KVIDEOWIDGET_H + +#include <qevent.h> +#include <qimage.h> +#include <qwidget.h> +#include <kmedia2.h> +#include <kxmlguiclient.h> + + +class KDE_ARTS_EXPORT KVideoWidget : public QWidget, virtual public KXMLGUIClient +{ +Q_OBJECT + +public: + KVideoWidget( KXMLGUIClient *clientParent, QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + KVideoWidget( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + virtual ~KVideoWidget(); + + void embed( Arts::VideoPlayObject vpo ); + static QImage snapshot( Arts::VideoPlayObject vpo ); + + bool isEmbedded(); + bool isFullscreen(); + bool isHalfSize(); + bool isNormalSize(); + bool isDoubleSize(); + + QSize sizeHint() const; + + virtual int heightForWidth ( int w ) const; + +protected: + virtual void mousePressEvent( QMouseEvent *event ); + virtual void mouseDoubleClickEvent( QMouseEvent *event); + virtual void resizeEvent( QResizeEvent *event ); + virtual bool x11Event( XEvent *event ); + +public slots: + void setFullscreen(); + void setWindowed(); + void setHalfSize(); + void setNormalSize(); + void setDoubleSize(); + + void resizeNotify( int width, int height ); + +protected slots: + void fullscreenActivated(); + void halfSizeActivated(); + void normalSizeActivated(); + void doubleSizeActivated(); + +signals: + void adaptSize( int width, int height ); + void mouseButtonPressed( int type, const QPoint &, int state ); + void mouseButtonDoubleClick( const QPoint &, int state ); + /** + * @deprecated + * use mouseButtonPressed( int type, const QPoint & ) instead. + */ + void rightButtonPressed( const QPoint & ); + +private: + void init(void); + QWidget *fullscreenWidget; + int videoWidth; + int videoHeight; + Arts::VideoPlayObject poVideo; +}; + +#endif diff --git a/arts/kde/mcop-dcop/Makefile.am b/arts/kde/mcop-dcop/Makefile.am new file mode 100644 index 000000000..6e2b90eac --- /dev/null +++ b/arts/kde/mcop-dcop/Makefile.am @@ -0,0 +1,20 @@ + +INCLUDES= -I$(includedir)/arts -I$(top_srcdir)/arts/kde $(all_includes) + +bin_PROGRAMS= +lib_LTLIBRARIES = +kdeinit_LTLIBRARIES = kmcop.la + +kmcop_la_SOURCES = mcopdcopobject.cpp kmcop.cpp kmcop.skel +kmcop_la_LIBADD = ../libartskde.la +kmcop_la_LDFLAGS = $(all_libraries) -module -avoid-version +kmcop_la_METASOURCES = AUTO + +noinst_HEADERS = kmcop.h + +kdelnkdir = $(kde_servicesdir) +kdelnk_DATA = kmcop.desktop + +messages: + $(XGETTEXT) kmcop.cpp -o $(podir)/kmcop.pot + diff --git a/arts/kde/mcop-dcop/kmcop.cpp b/arts/kde/mcop-dcop/kmcop.cpp new file mode 100644 index 000000000..22e19dc9d --- /dev/null +++ b/arts/kde/mcop-dcop/kmcop.cpp @@ -0,0 +1,171 @@ +/* + Copyright (c) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <kdebug.h> +#include <kuniqueapplication.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <dcopclient.h> + +#include <qvaluelist.h> +#include <qcstring.h> + +#include <kartsdispatcher.h> +#include <soundserver.h> +#include <dispatcher.h> +#include <object.h> +#include <core.h> + +#include "mcopdcopobject.h" + +#include "kmcop.moc" + +using namespace Arts; +using namespace std; + +class KMCOPPrivate +{ +public: + MCOPInfo mcopInfo; + QPtrList<MCOPDCOPObject> list; +}; + +int main(int argc, char **argv) +{ + KAboutData aboutdata("kmcop", I18N_NOOP("KMCOP"), + "0.1", I18N_NOOP("KDE MCOP-DCOP Bridge"), + KAboutData::License_GPL, "(C) 2001, Nikolas Zimmermann"); + aboutdata.addAuthor("Nikolas Zimmermann", I18N_NOOP("Author"), "wildfox@kde.org"); + + KCmdLineArgs::init(argc, argv, &aboutdata); + KUniqueApplication::addCmdLineOptions(); + + if(!KUniqueApplication::start()) + { + kdDebug() << "Running kmcop found" << endl; + return 0; + } + + KUniqueApplication app; + app.disableSessionManagement(); + + KArtsDispatcher dispatcher; + + KMCOP notify; + app.dcopClient()->setDefaultObject("arts"); + app.dcopClient()->setDaemonMode(true); + + return app.exec(); +} + +KMCOP::KMCOP() : QObject(), DCOPObject("arts") +{ + d = new KMCOPPrivate(); + d->mcopInfo = Reference("global:Arts_MCOPInfo"); + d->list.setAutoDelete(true); +} + +KMCOP::~KMCOP() +{ + delete d; +} + +int KMCOP::objectCount() +{ + return d->mcopInfo.objectCount(); +} + +QCString KMCOP::correctType(const QCString &str) +{ + if(str == "string") + return "QCString"; + return str; +} + +void KMCOP::addInterfacesHackHackHack() +{ + for(int i = 0; i <= objectCount(); i++) + { + Arts::Object obj = d->mcopInfo.objectForNumber(i); + + if(!obj.isNull()) + { + QCString interfaceName = obj._interfaceName().c_str(); + + if(interfaceName != "Arts::TraderOffer") + { + Arts::InterfaceRepo ifaceRepo = Dispatcher::the()->interfaceRepo(); + + MCOPDCOPObject *interface = new MCOPDCOPObject(interfaceName); + d->list.append(interface); + + InterfaceDef ifaceDef = ifaceRepo.queryInterface(string(interfaceName)); + vector<MethodDef> ifaceMethods = ifaceDef.methods; + + vector<MethodDef>::iterator ifaceMethodsIterator; + for(ifaceMethodsIterator = ifaceMethods.begin(); ifaceMethodsIterator != ifaceMethods.end(); ifaceMethodsIterator++) + { + QCString function, signature; + + MCOPEntryInfo *entry = new MCOPEntryInfo(); + + MethodDef currentMethod = *ifaceMethodsIterator; + vector<ParamDef> currentParameters = currentMethod.signature; + + QCString newType = correctType(QCString(currentMethod.type.c_str())); + + entry->setFunctionType(newType); + entry->setFunctionName(QCString(currentMethod.name.c_str())); + + function = entry->functionType() + QCString(" ") + entry->functionName() + QCString("("); + + signature = QCString("("); + + QCStringList signatureList; + + vector<ParamDef>::iterator methodParametersIterator; + for(methodParametersIterator = currentParameters.begin(); methodParametersIterator != currentParameters.end(); methodParametersIterator++) + { + ParamDef parameter = *methodParametersIterator; + if(methodParametersIterator != currentParameters.begin()) + { + function += QCString(", "); + signature += QCString(","); + } + + QCString correctParameter = correctType(QCString(parameter.type.c_str())); + + function += correctParameter; + signature += correctParameter; + + signatureList.append(QCString(parameter.type.c_str())); + } + + function += QCString(")"); + signature += QCString(")"); + + entry->setSignature(signature); + entry->setSignatureList(signatureList); + + interface->addDynamicFunction(function, entry); + } + } + } + } +} diff --git a/arts/kde/mcop-dcop/kmcop.desktop b/arts/kde/mcop-dcop/kmcop.desktop new file mode 100644 index 000000000..4e6400ef1 --- /dev/null +++ b/arts/kde/mcop-dcop/kmcop.desktop @@ -0,0 +1,90 @@ +[Desktop Entry] +Type=Service +Name=KMCOP +Name[hi]=के-एमकॉप +Name[te]=కెఎంకాప్ +Exec=kmcop +Comment=KDE MCOP-DCOP Bridge +Comment[af]=KDE MCOP-DCOP Brug +Comment[ar]=جسر KDE MCOP-DCOP +Comment[az]=KDE MCOP-DCOP Körpüsü +Comment[be]=Сувязь MCOP/DCOP +Comment[bn]=কে.ডি.ই MCOP-DCOP ব্রিজ +Comment[br]=Pont KDE MCOP-DCOP +Comment[bs]=KDE MCOP-DCOP prelaz +Comment[ca]=Connector MCOP-DCOP per al KDE +Comment[cs]=KDE MCOP-DCOP můstek +Comment[csb]=Mostk KDE MCOP-DCOP +Comment[cy]=Pont MCOP-DCOP KDE +Comment[da]=KDE MCOP-DCOP-bro +Comment[de]=Verbindung zwischen MCOP und DCOP +Comment[el]=Γέφυρα MCOP-DCOP του KDE +Comment[eo]=KDE-ponto inter MCOP-DCOP +Comment[es]=Puente KDE MCOP-DCOP +Comment[et]=KDE MCOP-DCOP sild +Comment[eu]=KDEren MCOP-DCOP zubia +Comment[fa]=پل KDE MCOP-DCOP +Comment[fi]=MCOP-DCOP -silta +Comment[fo]=KDE MCOP-DCOP-brúgv +Comment[fr]=Passerelle MCOP-DCOP pour KDE +Comment[ga]=Droichead KDE idir MCOP agus DCOP +Comment[gl]=Ponte MCOP-DCOP de KDE +Comment[he]=גשר MCOP-DCOP ל־KDE +Comment[hi]=केडीई MCOP-डीकॉप ब्रिज +Comment[hr]=KDE most MCOP-DCOP +Comment[hsb]=KDE MCOP-DCOP-móst +Comment[hu]=KDE MCOP-DCOP összekötőprogram +Comment[id]=Jembatan KDE MCOP-DCOP +Comment[is]=KDE MCOP-DCOP brú +Comment[it]=Ponte MCOP-DCOP per KDE +Comment[ja]=KDE MCOP-DCOP ブリッジ +Comment[ka]=KDE MCOP-DCOP ხიდი +Comment[kk]=KDE MCOP-DCOP көпірі +Comment[ko]=KDE MCOP-DCOP 브릿지 +Comment[lb]=KDE-MCOP-DCOP-Bréck +Comment[lt]=KDE MCOP-DCOP tiltas +Comment[lv]=KDE MCOP-DCOP Tilts +Comment[mk]=KDE MCOP-DCOP Мост +Comment[mn]=KDE-н MCOP ба DCOP хоорондын гүүр +Comment[ms]=Jambatan KDE MCOP-DCOP +Comment[mt]=Pont bejn MCOP u DCOP +Comment[nb]=KDE MCOP-DCOP Bro +Comment[nds]=KDE-Brüch twischen MCOP un DCOP +Comment[ne]=KDE MCOP-DCOP ब्रिज +Comment[nn]=MCOP-DCOP-bru for KDE +Comment[nso]=Leporogo la KDE MCOP-DCOP +Comment[pa]=KDE MCOP-DCOP ਪੁੱਲ +Comment[pl]=Mostek MCOP-DCOP +Comment[pt]=Ponte MCOP-DCOP para o KDE +Comment[pt_BR]=Ligação KDE MCOP-DCOP +Comment[ro]=Punte MCOP-DCOP KDE +Comment[ru]=Мост MCOP-DCOP +Comment[rw]=Iteme MCOP-DCOP KDE +Comment[se]=KDE MCOP-DCOP šaldi +Comment[sk]=Most KDE MCOP-DCOP +Comment[sl]=Premostitelj MCOP-DCOP za KDE +Comment[sq]=Ura e KDE MCOP-DCOP-it +Comment[sr]=KDED MCOP-DCOP мост +Comment[sr@Latn]=KDED MCOP-DCOP most +Comment[ss]=Libhuloho le MCOP-DCOP ku KDE +Comment[sv]=KDE MCOP-DCOP-brygga +Comment[ta]=கேடிஇ MCOP-DCOP பாலம் +Comment[te]=కెడిఈ ఎంసిఓపి-డిసిఓపి వారధి +Comment[tg]=Пайвасти KDE MCOP-DCOP +Comment[th]=ตัวเชื่อม KDE MCOP-DCOP +Comment[tr]=KDE MCOP-DCOP Köprüsü +Comment[tt]=KDE MCOP-DCOP Küpere +Comment[uk]=Міст KDE MCOP-DCOP +Comment[uz]=KDE MCOP-DCOP koʻprigi +Comment[uz@cyrillic]=KDE MCOP-DCOP кўприги +Comment[ven]=KDE MCOP-DCOP Buroho +Comment[vi]=Cầu MCOP-DCOP của KDE +Comment[xh]=KDE MCOP-DCOP Ibhulorho +Comment[zh_CN]=KDE MCOP-DCOP 桥 +Comment[zh_HK]=KDE MCOP-DCOP 橋樑 +Comment[zh_TW]=KDE MCOP-DCOP 橋樑 +Comment[zu]=Ibhulogo le-KDE MCOP-DCOP +Icon=kmcop +ServiceTypes=KMCOP +X-DCOP-ServiceType=Unique +X-KDE-StartupNotify=false diff --git a/arts/kde/mcop-dcop/kmcop.h b/arts/kde/mcop-dcop/kmcop.h new file mode 100644 index 000000000..c81e385ff --- /dev/null +++ b/arts/kde/mcop-dcop/kmcop.h @@ -0,0 +1,50 @@ +/* + Copyright (c) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KMCOP_H +#define KMCOP_H + +#include <qobject.h> + +#include <dcopobject.h> + +class KMCOPPrivate; + +class KMCOP : public QObject, + public DCOPObject +{ +Q_OBJECT +K_DCOP + +public: + KMCOP(); + ~KMCOP(); + +k_dcop: + int objectCount(); + void addInterfacesHackHackHack(); + +private: + QCString correctType(const QCString &str); + KMCOPPrivate *d; +}; + + +#endif + diff --git a/arts/kde/mcop-dcop/mcopdcopobject.cpp b/arts/kde/mcop-dcop/mcopdcopobject.cpp new file mode 100644 index 000000000..f1d1acad5 --- /dev/null +++ b/arts/kde/mcop-dcop/mcopdcopobject.cpp @@ -0,0 +1,152 @@ +/* + Copyright (c) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <kdebug.h> + +#include <core.h> +//#include <object.h> +//#include <reference.h> +#include <dynamicrequest.h> + +#include <qmap.h> +#include <qdatastream.h> + +using namespace std; + +#include "mcopdcoptools.h" +#include "mcopdcopobject.h" + +class MCOPDCOPObjectPrivate +{ +public: + QMap<QCString, MCOPEntryInfo *> dynamicFunctions; +}; + +MCOPDCOPObject::MCOPDCOPObject(QCString name) : DCOPObject(name) +{ + d = new MCOPDCOPObjectPrivate(); +} + +MCOPDCOPObject::~MCOPDCOPObject() +{ + delete d; +} + +QCStringList MCOPDCOPObject::functionsDynamic() +{ + QCStringList returnList; + + QMap<QCString, MCOPEntryInfo *>::iterator it; + for(it = d->dynamicFunctions.begin(); it != d->dynamicFunctions.end(); ++it) + returnList.append(it.key()); + + return returnList; +} + +Arts::Buffer *MCOPDCOPObject::callFunction(MCOPEntryInfo *entry, QCString ifaceName, const QByteArray &data) +{ + Arts::Object workingObject = Arts::SubClass(string(ifaceName)); + Arts::DynamicRequest request(workingObject); + request.method(string(entry->functionName())); + + if(entry->signatureList().size() > 0) + { + QCStringList list = entry->signatureList(); + + QCStringList::iterator it; + for(it = list.begin(); it != list.end(); ++it) + { + QCString param = *it; + + kdDebug() << "PARAM: " << param << endl; + + QDataStream argStream(data, IO_ReadOnly); + + if(param == "long") + request.param(MCOPDCOPTools::getLong(argStream)); + else if(param == "string") + request.param(MCOPDCOPTools::getString(argStream)); + } + } + + Arts::AnyRef result; + if(!request.invoke(result)) + return 0; + + Arts::Buffer *newBuffer = new Arts::Buffer(); + result.write(newBuffer); + + return newBuffer; +} + +bool MCOPDCOPObject::processDynamic(const QCString &fun, const QByteArray &data, QCString &replyType, QByteArray &replyData) +{ + QMap<QCString, MCOPEntryInfo *>::iterator it; + for(it = d->dynamicFunctions.begin(); it != d->dynamicFunctions.end(); ++it) + { + MCOPEntryInfo *entry = it.data(); + + if((entry->functionName() + entry->signature()) == fun) + { + QCString type = entry->functionType(); + + if(type == "void") + { + replyType = type; + + Arts::Buffer *result = callFunction(entry, objId(), data); + + if(result != 0) + delete result; + } + else if(type == "string") + { + replyType = "QCString"; + + QDataStream reply(replyData, IO_WriteOnly); + reply << "fooo!"; + } + else if(type == "long") + { + replyType = type; + + long returnCode = -1; + + Arts::Buffer *result = callFunction(entry, objId(), data); + + if(result != 0) + { + returnCode = result->readLong(); + delete result; + } + + QDataStream reply(replyData, IO_WriteOnly); + reply << returnCode; + } + + return true; + } + } + + return false; +} + +void MCOPDCOPObject::addDynamicFunction(QCString value, MCOPEntryInfo *entry) +{ + d->dynamicFunctions.insert(value, entry); +} diff --git a/arts/kde/mcop-dcop/mcopdcopobject.h b/arts/kde/mcop-dcop/mcopdcopobject.h new file mode 100644 index 000000000..4c7e70cf5 --- /dev/null +++ b/arts/kde/mcop-dcop/mcopdcopobject.h @@ -0,0 +1,89 @@ +/* + Copyright (c) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef MCOPDCOPOBJECT_H +#define MCOPDCOPOBJECT_H + +#include <dcopobject.h> + +#include <qvaluelist.h> +#include <qcstring.h> + +typedef QValueList<QCString> QCStringList; + +class MCOPDCOPObjectPrivate; + +class MCOPEntryInfo +{ +public: + MCOPEntryInfo() + { } + + ~MCOPEntryInfo() + { } + + QCString functionType() + { return m_functionType; } + + QCString functionName() + { return m_functionName; } + + QCString signature() + { return m_signature; } + + QCStringList signatureList() + { return m_signatureList; } + + void setFunctionType(QCString s) + { m_functionType = s; } + + void setFunctionName(QCString s) + { m_functionName = s; } + + void setSignature(QCString s) + { m_signature = s; } + + void setSignatureList(QCStringList s) + { m_signatureList = s; } + +private: + QCString m_functionType, m_functionName, m_signature; + QCStringList m_signatureList; +}; + +class MCOPDCOPObject : public DCOPObject +{ +public: + MCOPDCOPObject(QCString name); + ~MCOPDCOPObject(); + + virtual bool processDynamic(const QCString &fun, const QByteArray &data, QCString &replyType, QByteArray &replyData); + virtual QCStringList functionsDynamic(); + + void addDynamicFunction(QCString value, MCOPEntryInfo *entry); + + Arts::Buffer *callFunction(MCOPEntryInfo *entry, QCString ifaceName, const QByteArray &data); + +private: + MCOPDCOPObjectPrivate *d; +}; + + +#endif + diff --git a/arts/kde/mcop-dcop/mcopdcoptools.h b/arts/kde/mcop-dcop/mcopdcoptools.h new file mode 100644 index 000000000..f1279111c --- /dev/null +++ b/arts/kde/mcop-dcop/mcopdcoptools.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 2001 Nikolas Zimmermann <wildfox@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef MCOPDCOPTOOLS_H +#define MCOPDCOPTOOLS_H + +#include <string> + +#include <qdatastream.h> + +class MCOPDCOPTools +{ +public: + static long getLong(QDataStream &stream) + { + long l; + stream << l; + + return l; + } + + static std::string getString(QDataStream &stream) + { + QCString s; + stream << s; + + return std::string(s); + } +}; + +#endif diff --git a/arts/knotify/Makefile.am b/arts/knotify/Makefile.am new file mode 100644 index 000000000..bf743ce45 --- /dev/null +++ b/arts/knotify/Makefile.am @@ -0,0 +1,27 @@ + +INCLUDES= -I$(top_srcdir)/arts/kde -I$(includedir)/arts $(all_includes) + +####### Files + +kde_module_LTLIBRARIES = knotify.la + +knotify_la_SOURCES = knotify.cpp knotify.skel +if include_ARTS +knotify_la_LIBADD = -lsoundserver_idl -lqtmcop $(LIB_KDEUI) $(top_builddir)/arts/kde/libartskde.la +endif +knotify_la_LDFLAGS = $(all_libraries) -module -avoid-version +knotify_la_METASOURCES = AUTO + +check_PROGRAMS = knotifytest +knotifytest_SOURCES = knotifytest.cpp +knotifytest_LDADD = $(LIB_KDECORE) +knotifytest_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +noinst_HEADERS = knotify.h + +kdelnkdir = $(kde_servicesdir) +kdelnk_DATA = knotify.desktop + +messages: + $(XGETTEXT) knotify.cpp -o $(podir)/knotify.pot + diff --git a/arts/knotify/README b/arts/knotify/README new file mode 100644 index 000000000..3257cdc33 --- /dev/null +++ b/arts/knotify/README @@ -0,0 +1,33 @@ +About KNotify + +Historic overview. From KDE-1 to KDE-2: +--------------------------------------- +KDE-1 ships with a notification system for window manager events - a sound +could be played for example on startup or when a window closes. This was a +very limited notification system. + +KNotify in contrast is a very flexible notification system. It can easily be +accessed by any application, and notifications can have several +presentations: Sound is still supported, but you can as well display a +message box, write a text to a log file or log window. + +The notification presentation will be user configurable. Some people don't +like message boxes popping up at unexpected times, so they prefer sounds +instead. Deaf people on the otehr hand will not be happy about desktop +sounds. + + + +Usage: +------ +1. Compile +2. Start knotify +3. Test it with knotifyclient. + +Ideas: +------ +It might be useful to modify message presentation from time to time. For +example, while the screen is locked, it is very likely that the user is not +present. Thus, he will not be able to hear a "You have mail" sound (or to +see a talk request). Re-routing this to a log window sounds like a very good +idea. diff --git a/arts/knotify/knotify.cpp b/arts/knotify/knotify.cpp new file mode 100644 index 000000000..794ef3dcd --- /dev/null +++ b/arts/knotify/knotify.cpp @@ -0,0 +1,800 @@ +/* + Copyright (c) 1997 Christian Esken (esken@kde.org) + 2000 Charles Samuels (charles@kde.org) + 2000 Stefan Schimanski (1Stein@gmx.de) + 2000 Matthias Ettrich (ettrich@kde.org) + 2000 Waldo Bastian <bastian@kde.org> + 2000-2003 Carsten Pfeiffer <pfeiffer@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +// C headers +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <config.h> +#ifndef WITHOUT_ARTS +// aRts headers +#include <connect.h> +#include <dispatcher.h> +#include <flowsystem.h> +#include <qiomanager.h> +#include <soundserver.h> +#endif + +// QT headers +#include <qfile.h> +#include <qfileinfo.h> +#include <qstringlist.h> +#include <qtextstream.h> + +// KDE headers +#include <dcopclient.h> +#include <kaboutdata.h> +#ifndef WITHOUT_ARTS +#include <kartsdispatcher.h> +#include <kartsserver.h> +#endif +#include <kcmdlineargs.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpassivepopup.h> +#include <kiconloader.h> +#include <kmacroexpander.h> +#ifndef WITHOUT_ARTS +#include <kplayobjectfactory.h> +#include <kaudiomanagerplay.h> +#endif +#include <kprocess.h> +#include <kstandarddirs.h> +#include <kuniqueapplication.h> +#include <kwin.h> + +#include "knotify.h" +#include "knotify.moc" + +class KNotifyPrivate +{ +public: + KConfig* globalEvents; + KConfig* globalConfig; + QMap<QString, KConfig*> events; + QMap<QString, KConfig*> configs; + QString externalPlayer; + KProcess *externalPlayerProc; + +#ifndef WITHOUT_ARTS + QPtrList<KDE::PlayObject> playObjects; + QMap<KDE::PlayObject*,int> playObjectEventMap; + KAudioManagerPlay *audioManager; +#endif + int externalPlayerEventId; + + bool useExternal; + bool useArts; + int volume; + QTimer *playTimer; + bool inStartup; + QString startupEvents; +}; + +// Yes, it's ugly to put this here, but this facilitates the cautious startup +// procedure. +#ifndef WITHOUT_ARTS +KArtsServer *soundServer = 0; +#endif + +extern "C"{ + +KDE_EXPORT int kdemain(int argc, char **argv) +{ + KAboutData aboutdata("knotify", I18N_NOOP("KNotify"), + "3.0", I18N_NOOP("KDE Notification Server"), + KAboutData::License_GPL, "(C) 1997-2003, KDE Developers"); + aboutdata.addAuthor("Carsten Pfeiffer",I18N_NOOP("Current Maintainer"),"pfeiffer@kde.org"); + aboutdata.addAuthor("Christian Esken",0,"esken@kde.org"); + aboutdata.addAuthor("Stefan Westerfeld",I18N_NOOP("Sound support"),"stefan@space.twc.de"); + aboutdata.addAuthor("Charles Samuels",I18N_NOOP("Previous Maintainer"),"charles@kde.org"); + + KCmdLineArgs::init( argc, argv, &aboutdata ); + KUniqueApplication::addCmdLineOptions(); + + + // initialize application + if ( !KUniqueApplication::start() ) { + kdDebug() << "Running knotify found" << endl; + return 0; + } + + KUniqueApplication app; + app.disableSessionManagement(); + + // KNotify is started on KDE startup and on demand (using + // KNotifClient::startDaemon()) whenever a KNotify event occurs. Especially + // KWin may fire many events (e.g. when a window pops up). When we have + // problems with aRts or the installation, we might get an infinite loop + // of knotify crashing, popping up the crashhandler window and kwin firing + // another event, starting knotify again... + // We try to prevent this by tracking our startup and offer options to + // abort this. + +#ifndef WITHOUT_ARTS + KConfigGroup config( KGlobal::config(), "StartProgress" ); + KConfig artsKCMConfig( "kcmartsrc" ); + artsKCMConfig.setGroup( "Arts" ); + bool useArts = artsKCMConfig.readBoolEntry( "StartServer", true ); + if (useArts) + useArts = config.readBoolEntry( "Use Arts", useArts ); + bool ok = config.readBoolEntry( "Arts Init", true ); + + if ( useArts && !ok ) + { + if ( KMessageBox::questionYesNo( + 0L, + i18n("During the previous startup, KNotify crashed while creating " + "Arts::Dispatcher. Do you want to try again or disable " + "aRts sound output?\n\n" + "If you choose to disable aRts output now, you can re-enable " + "it later or select an alternate sound player " + "in the System Notifications control panel."), + i18n("KNotify Problem"), + i18n("&Try Again"), + i18n("D&isable aRts Output"), + "KNotifyStartProgress", + 0 /* don't call KNotify :) */ + ) + == KMessageBox::No ) + { + useArts = false; + } + } + + // when ArtsDispatcher crashes, we know it the next start. + config.writeEntry( "Arts Init", false ); + config.writeEntry( "Use Arts", useArts ); + config.sync(); + + KArtsDispatcher *dispatcher = 0; + if ( useArts ) + { + dispatcher = new KArtsDispatcher; + soundServer = new KArtsServer; + } + + // ok, seemed to work. + config.writeEntry("Arts Init", useArts ); + config.sync(); + + ok = config.readBoolEntry( "KNotify Init", true ); + if ( useArts && !ok ) + { + if ( KMessageBox::questionYesNo( + 0L, + i18n("During the previous startup, KNotify crashed while instantiating " + "KNotify. Do you want to try again or disable " + "aRts sound output?\n\n" + "If you choose to disable aRts output now, you can re-enable " + "it later or select an alternate sound player " + "in the System Notifications control panel."), + i18n("KNotify Problem"), + i18n("&Try Again"), + i18n("D&isable aRts Output"), + "KNotifyStartProgress", + 0 /* don't call KNotify :) */ + ) + == KMessageBox::No ) + { + useArts = false; + delete soundServer; + soundServer = 0L; + delete dispatcher; + dispatcher = 0L; + } + } + + // when KNotify instantiation crashes, we know it the next start. + config.writeEntry( "KNotify Init", false ); + config.writeEntry( "Use Arts", useArts ); + config.sync(); + + // start notify service + KNotify *notify = new KNotify( useArts ); + + config.writeEntry( "KNotify Init", true ); + config.sync(); + +#else + + // start notify service, without aRts + KNotify *notify = new KNotify( false ); + +#endif + + app.dcopClient()->setDefaultObject( "Notify" ); + app.dcopClient()->setDaemonMode( true ); + // kdDebug() << "knotify starting" << endl; + + int ret = app.exec(); + delete notify; +#ifndef WITHOUT_ARTS + delete soundServer; + delete dispatcher; +#endif + return ret; +} +}// end extern "C" + +KNotify::KNotify( bool useArts ) + : QObject(), DCOPObject("Notify") +{ + d = new KNotifyPrivate; + d->globalEvents = new KConfig("knotify/eventsrc", true, false, "data"); + d->globalConfig = new KConfig("knotify.eventsrc", true, false); + d->externalPlayerProc = 0; + d->useArts = useArts; + d->inStartup = true; +#ifndef WITHOUT_ARTS + d->playObjects.setAutoDelete(true); + d->audioManager = 0; + if( useArts ) + { + connect( soundServer, SIGNAL( restartedServer() ), this, SLOT( restartedArtsd() ) ); + restartedArtsd(); //started allready need to initialize d->audioManager + } +#endif + + d->volume = 100; + + d->playTimer = 0; + + loadConfig(); +} + +KNotify::~KNotify() +{ + reconfigure(); + +#ifndef WITHOUT_ARTS + d->playObjects.clear(); + + delete d->globalEvents; + delete d->globalConfig; + delete d->externalPlayerProc; + delete d->audioManager; +#endif + delete d; +} + + +void KNotify::loadConfig() { + // load external player settings + KConfig *kc = KGlobal::config(); + kc->setGroup("Misc"); + d->useExternal = kc->readBoolEntry( "Use external player", false ); + d->externalPlayer = kc->readPathEntry("External player"); + + // try to locate a suitable player if none is configured + if ( d->externalPlayer.isEmpty() ) { + QStringList players; + players << "wavplay" << "aplay" << "auplay"; + QStringList::Iterator it = players.begin(); + while ( d->externalPlayer.isEmpty() && it != players.end() ) { + d->externalPlayer = KStandardDirs::findExe( *it ); + ++it; + } + } + + // load default volume + d->volume = kc->readNumEntry( "Volume", 100 ); +} + + +void KNotify::reconfigure() +{ + kapp->config()->reparseConfiguration(); + loadConfig(); + + // clear loaded config files + d->globalConfig->reparseConfiguration(); + for ( QMapIterator<QString,KConfig*> it = d->configs.begin(); it != d->configs.end(); ++it ) + delete it.data(); + d->configs.clear(); +} + + +void KNotify::notify(const QString &event, const QString &fromApp, + const QString &text, QString sound, QString file, + int present, int level) +{ + notify( event, fromApp, text, sound, file, present, level, 0, 1 ); +} + +void KNotify::notify(const QString &event, const QString &fromApp, + const QString &text, QString sound, QString file, + int present, int level, int winId) +{ + notify( event, fromApp, text, sound, file, present, level, winId, 1 ); +} + +void KNotify::notify(const QString &event, const QString &fromApp, + const QString &text, QString sound, QString file, + int present, int level, int winId, int eventId ) +{ + // kdDebug() << "event=" << event << " fromApp=" << fromApp << " text=" << text << " sound=" << sound << + // " file=" << file << " present=" << present << " level=" << level << " winId=" << winId << " eventId=" << eventId << endl; + if( d->inStartup ) { + d->startupEvents += "(" + event + ":" + fromApp + ")"; + } + + QString commandline; + KConfig *eventsFile = NULL; + KConfig *configFile = NULL; + + // check for valid events + if ( !event.isEmpty() ) { + + // get config file + if ( d->events.contains( fromApp ) ) { + eventsFile = d->events[fromApp]; + } else { + eventsFile=new KConfig(locate("data", fromApp+"/eventsrc"),true,false); + d->events.insert( fromApp, eventsFile ); + } + if ( d->configs.contains( fromApp) ) { + configFile = d->configs[fromApp]; + } else { + configFile=new KConfig(fromApp+".eventsrc",true,false); + d->configs.insert( fromApp, configFile ); + } + + if ( !eventsFile->hasGroup( event ) && isGlobal(event) ) + { + eventsFile = d->globalEvents; + configFile = d->globalConfig; + } + + eventsFile->setGroup( event ); + configFile->setGroup( event ); + + // get event presentation + if ( present==-1 ) + present = configFile->readNumEntry( "presentation", -1 ); + if ( present==-1 ) + present = eventsFile->readNumEntry( "default_presentation", 0 ); + + // get sound file name + if( present & KNotifyClient::Sound ) { + QString theSound = configFile->readPathEntry( "soundfile" ); + if ( theSound.isEmpty() ) + theSound = eventsFile->readPathEntry( "default_sound" ); + if ( !theSound.isEmpty() ) + sound = theSound; + } + + // get log file name + if( present & KNotifyClient::Logfile ) { + QString theFile = configFile->readPathEntry( "logfile" ); + if ( theFile.isEmpty() ) + theFile = eventsFile->readPathEntry( "default_logfile" ); + if ( !theFile.isEmpty() ) + file = theFile; + } + + // get default event level + if( present & KNotifyClient::Messagebox ) + level = eventsFile->readNumEntry( "level", 0 ); + + // get command line + if (present & KNotifyClient::Execute ) { + commandline = configFile->readPathEntry( "commandline" ); + if ( commandline.isEmpty() ) + commandline = eventsFile->readPathEntry( "default_commandline" ); + } + } + + // emit event + if ( present & KNotifyClient::Sound ) // && QFile(sound).isReadable() + notifyBySound( sound, fromApp, eventId ); + + if ( present & KNotifyClient::Execute ) + notifyByExecute( commandline, event, fromApp, text, winId, eventId ); + + if ( present & KNotifyClient::Logfile ) // && QFile(file).isWritable() + notifyByLogfile( text, file ); + + if ( present & KNotifyClient::Stderr ) + notifyByStderr( text ); + + if ( present & KNotifyClient::Taskbar ) + notifyByTaskbar( checkWinId( fromApp, winId )); + + if ( present & KNotifyClient::PassivePopup ) + notifyByPassivePopup( text, fromApp, eventsFile, checkWinId( fromApp, winId )); + else if ( present & KNotifyClient::Messagebox ) + notifyByMessagebox( text, level, checkWinId( fromApp, winId )); + + QByteArray qbd; + QDataStream ds(qbd, IO_WriteOnly); + ds << event << fromApp << text << sound << file << present << level + << winId << eventId; + emitDCOPSignal("notifySignal(QString,QString,QString,QString,QString,int,int,int,int)", qbd); + +} + + +bool KNotify::notifyBySound( const QString &sound, const QString &appname, int eventId ) +{ + if (sound.isEmpty()) { + soundFinished( eventId, NoSoundFile ); + return false; + } + + bool external = d->useExternal && !d->externalPlayer.isEmpty(); + // get file name + QString soundFile(sound); + if ( QFileInfo(sound).isRelative() ) + { + QString search = QString("%1/sounds/%2").arg(appname).arg(sound); + soundFile = KGlobal::instance()->dirs()->findResource("data", search); + if ( soundFile.isEmpty() ) + soundFile = locate( "sound", sound ); + } + if ( soundFile.isEmpty() || isPlaying( soundFile ) ) + { + soundFinished( eventId, soundFile.isEmpty() ? NoSoundFile : FileAlreadyPlaying ); + return false; + } + + + // kdDebug() << "KNotify::notifyBySound - trying to play file " << soundFile << endl; + + if (!external) { + //If we disabled using aRts, just return, + //(If we don't, we'll blow up accessing the null soundServer) + if (!d->useArts) + { + soundFinished( eventId, NoSoundSupport ); + return false; + } + +#ifndef WITHOUT_ARTS + // play sound finally + while( d->playObjects.count()>5 ) + abortFirstPlayObject(); + + KDE::PlayObjectFactory factory(soundServer->server()); + if( d->audioManager ) + factory.setAudioManagerPlay( d->audioManager ); + KURL soundURL; + soundURL.setPath(soundFile); + KDE::PlayObject *playObject = factory.createPlayObject(soundURL, false); + + if (playObject->isNull()) + { + soundFinished( eventId, NoSoundSupport ); + delete playObject; + return false; + } + + if ( d->volume != 100 ) + { + // It works to access the playObject immediately because we don't allow + // non-file URLs for sounds. + Arts::StereoVolumeControl volumeControl = Arts::DynamicCast(soundServer->server().createObject("Arts::StereoVolumeControl")); + Arts::PlayObject player = playObject->object(); + Arts::Synth_AMAN_PLAY ap = d->audioManager->amanPlay(); + if( ! volumeControl.isNull() && ! player.isNull() && ! ap.isNull() ) + { + volumeControl.scaleFactor( d->volume/100.0 ); + + ap.stop(); + Arts::disconnect( player, "left", ap, "left" ); + Arts::disconnect( player, "right", ap, "right" ); + + ap.start(); + volumeControl.start(); + + Arts::connect(player,"left",volumeControl,"inleft"); + Arts::connect(player,"right",volumeControl,"inright"); + + Arts::connect(volumeControl,"outleft",ap,"left"); + Arts::connect(volumeControl,"outright",ap,"right"); + + player._addChild( volumeControl, "volume" ); + } + } + + playObject->play(); + d->playObjects.append( playObject ); + d->playObjectEventMap.insert( playObject, eventId ); + + if ( !d->playTimer ) + { + d->playTimer = new QTimer( this ); + connect( d->playTimer, SIGNAL( timeout() ), SLOT( playTimeout() ) ); + } + if ( !d->playTimer->isActive() ) + d->playTimer->start( 1000 ); +#endif + return true; + + } else if(!d->externalPlayer.isEmpty()) { + // use an external player to play the sound + KProcess *proc = d->externalPlayerProc; + if (!proc) + { + proc = d->externalPlayerProc = new KProcess; + connect( proc, SIGNAL( processExited( KProcess * )), + SLOT( slotPlayerProcessExited( KProcess * ))); + } + if (proc->isRunning()) + { + soundFinished( eventId, PlayerBusy ); + return false; // Skip + } + proc->clearArguments(); + (*proc) << d->externalPlayer << QFile::encodeName( soundFile ); + d->externalPlayerEventId = eventId; + proc->start(KProcess::NotifyOnExit); + return true; + } + + soundFinished( eventId, Unknown ); + return false; +} + +bool KNotify::notifyByMessagebox(const QString &text, int level, WId winId) +{ + // ignore empty messages + if ( text.isEmpty() ) + return false; + + // display message box for specified event level + switch( level ) { + default: + case KNotifyClient::Notification: + KMessageBox::informationWId( winId, text, i18n("Notification"), 0, false ); + break; + case KNotifyClient::Warning: + KMessageBox::sorryWId( winId, text, i18n("Warning"), false ); + break; + case KNotifyClient::Error: + KMessageBox::errorWId( winId, text, i18n("Error"), false ); + break; + case KNotifyClient::Catastrophe: + KMessageBox::errorWId( winId, text, i18n("Catastrophe!"), false ); + break; + } + + return true; +} + +bool KNotify::notifyByPassivePopup( const QString &text, + const QString &appName, + KConfig* eventsFile, + WId senderWinId ) +{ + KIconLoader iconLoader( appName ); + if ( eventsFile != NULL ) { + KConfigGroup config( eventsFile, "!Global!" ); + QString iconName = config.readEntry( "IconName", appName ); + QPixmap icon = iconLoader.loadIcon( iconName, KIcon::Small ); + QString title = config.readEntry( "Comment", appName ); + KPassivePopup::message(title, text, icon, senderWinId); + } else + kdError() << "No events for app " << appName << "defined!" <<endl; + + return true; +} + +bool KNotify::notifyByExecute(const QString &command, const QString& event, + const QString& fromApp, const QString& text, + int winId, int eventId) { + if (!command.isEmpty()) { + // kdDebug() << "executing command '" << command << "'" << endl; + QMap<QChar,QString> subst; + subst.insert( 'e', event ); + subst.insert( 'a', fromApp ); + subst.insert( 's', text ); + subst.insert( 'w', QString::number( winId )); + subst.insert( 'i', QString::number( eventId )); + QString execLine = KMacroExpander::expandMacrosShellQuote( command, subst ); + if ( execLine.isEmpty() ) + execLine = command; // fallback + + KProcess p; + p.setUseShell(true); + p << execLine; + p.start(KProcess::DontCare); + return true; + } + return false; +} + + +bool KNotify::notifyByLogfile(const QString &text, const QString &file) +{ + // ignore empty messages + if ( text.isEmpty() ) + return true; + + // open file in append mode + QFile logFile(file); + if ( !logFile.open(IO_WriteOnly | IO_Append) ) + return false; + + // append msg + QTextStream strm( &logFile ); + strm << "- KNotify " << QDateTime::currentDateTime().toString() << ": "; + strm << text << endl; + + // close file + logFile.close(); + return true; +} + +bool KNotify::notifyByStderr(const QString &text) +{ + // ignore empty messages + if ( text.isEmpty() ) + return true; + + // open stderr for output + QTextStream strm( stderr, IO_WriteOnly ); + + // output msg + strm << "KNotify " << QDateTime::currentDateTime().toString() << ": "; + strm << text << endl; + + return true; +} + +bool KNotify::notifyByTaskbar( WId win ) +{ + if( win == 0 ) + return false; + KWin::demandAttention( win ); + return true; +} + +bool KNotify::isGlobal(const QString &eventname) +{ + return d->globalEvents->hasGroup( eventname ); +} + +void KNotify::setVolume( int volume ) +{ + if ( volume<0 ) volume=0; + if ( volume>=100 ) volume=100; + d->volume = volume; +} + +void KNotify::playTimeout() +{ +#ifndef WITHOUT_ARTS + for ( QPtrListIterator< KDE::PlayObject > it(d->playObjects); *it;) + { + QPtrListIterator< KDE::PlayObject > current = it; + ++it; + if ( (*current)->state() != Arts::posPlaying ) + { + QMap<KDE::PlayObject*,int>::Iterator eit = d->playObjectEventMap.find( *current ); + if ( eit != d->playObjectEventMap.end() ) + { + soundFinished( *eit, PlayedOK ); + d->playObjectEventMap.remove( eit ); + } + d->playObjects.remove( current ); + } + } + if ( !d->playObjects.count() ) + d->playTimer->stop(); +#endif +} + +bool KNotify::isPlaying( const QString& soundFile ) const +{ +#ifndef WITHOUT_ARTS + for ( QPtrListIterator< KDE::PlayObject > it(d->playObjects); *it; ++it) + { + if ( (*it)->mediaName() == soundFile ) + return true; + } +#endif + return false; +} + +void KNotify::slotPlayerProcessExited( KProcess *proc ) +{ + soundFinished( d->externalPlayerEventId, + (proc->normalExit() && proc->exitStatus() == 0) ? PlayedOK : Unknown ); +} + +void KNotify::abortFirstPlayObject() +{ +#ifndef WITHOUT_ARTS + QMap<KDE::PlayObject*,int>::Iterator it = d->playObjectEventMap.find( d->playObjects.getFirst() ); + if ( it != d->playObjectEventMap.end() ) + { + soundFinished( it.data(), Aborted ); + d->playObjectEventMap.remove( it ); + } + d->playObjects.removeFirst(); +#endif +} + +void KNotify::soundFinished( int eventId, PlayingFinishedStatus reason ) +{ + QByteArray data; + QDataStream stream( data, IO_WriteOnly ); + stream << eventId << (int) reason; + + DCOPClient::mainClient()->emitDCOPSignal( "KNotify", "playingFinished(int,int)", data ); +} + +WId KNotify::checkWinId( const QString &appName, WId senderWinId ) +{ + if ( senderWinId == 0 ) + { + QCString senderId = kapp->dcopClient()->senderId(); + QCString compare = (appName + "-mainwindow").latin1(); + int len = compare.length(); + // kdDebug() << "notifyByPassivePopup: appName=" << appName << " sender=" << senderId << endl; + + QCStringList objs = kapp->dcopClient()->remoteObjects( senderId ); + for (QCStringList::ConstIterator it = objs.begin(); it != objs.end(); ++it ) { + QCString obj( *it ); + if ( obj.left(len) == compare) { + // kdDebug( ) << "found " << obj << endl; + QCString replyType; + QByteArray data, replyData; + + if ( kapp->dcopClient()->call(senderId, obj, "getWinID()", data, replyType, replyData) ) { + QDataStream answer(replyData, IO_ReadOnly); + if (replyType == "int") { + answer >> senderWinId; + // kdDebug() << "SUCCESS, found getWinID(): type='" << QString(replyType) + // << "' senderWinId=" << senderWinId << endl; + } + } + } + } + } + return senderWinId; +} + +void KNotify::restartedArtsd() +{ +#ifndef WITHOUT_ARTS + delete d->audioManager; + d->audioManager = new KAudioManagerPlay( soundServer ); + d->audioManager->setTitle( i18n( "KDE System Notifications" ) ); + d->audioManager->setAutoRestoreID( "KNotify Aman Play" ); +#endif +} + +void KNotify::sessionReady() +{ + if( d->inStartup && !d->startupEvents.isEmpty()) + kdDebug() << "There were knotify events while startup:" << d->startupEvents << endl; + d->inStartup = false; +} + +// vim: sw=4 sts=4 ts=8 et diff --git a/arts/knotify/knotify.desktop b/arts/knotify/knotify.desktop new file mode 100644 index 000000000..da950fa8a --- /dev/null +++ b/arts/knotify/knotify.desktop @@ -0,0 +1,119 @@ +[Desktop Entry] +Type=Service +Name=KNotify +Name[af]=Knotify +Name[ar]=برنامج الإبلاغ +Name[bn]=কে-নোটিফাই +Name[csb]=Òdkôzanié +Name[cy]=KHysbyu +Name[eo]=Katentigilo +Name[fo]=KÁminning +Name[hi]=के-नोटिफाई +Name[ka]=სისტემური შეტყობინება +Name[ko]=K알림이 +Name[mn]=Сонордуулга +Name[ne]=केनोटिफाइ +Name[nso]=KLemosa +Name[pa]=ਕੇਟਿੱਪਣੀ +Name[pl]=Powiadamianie +Name[pt_BR]=Notificações +Name[ru]=Системные сообщения +Name[ss]=KNotify +Name[sv]=Knotify +Name[ta]=கேகுறிப்பெடு +Name[te]=కెనోటిఫై +Name[tg]=Хабарҳои системавӣ +Name[th]=ระบบแจ้งเตือน - K +Name[ven]=U divhadza ha K +Name[zu]=I-KNotify +Exec=knotify +Comment=KDE Notification Daemon +Comment[af]=Kde Inkennisstelling Bediener +Comment[ar]=مراقب تنبيهات كيدي +Comment[az]=KDE Bildiriş Demonu +Comment[be]=Сервіс нагадванняў KDE +Comment[bg]=Сървър за съобщения +Comment[bn]=কে.ডি.ই নোটিশ সরবরাহকারী ডিমন +Comment[br]=Diaoul Kemennadenn KDE +Comment[bs]=KDE Sistemska obavještenja +Comment[ca]=Dimoni de notificacions per al KDE +Comment[cs]=Démon pro systémová hlášení prostředí KDE +Comment[csb]=Demon òdkôzëwaniô KDE +Comment[cy]=Daemon Hysbysu KDE +Comment[da]=KDE Bekendtgørelsesdæmon +Comment[de]=KDE-Benachrichtigungsprogramm +Comment[el]=Δαίμονας ειδοποίησης του KDE +Comment[eo]=KDE-Sistematentigo-demono +Comment[es]=Demonio de notificación de KDE +Comment[et]=KDE süsteemsete märguannete deemon +Comment[eu]=KDEko jakinarazpenaren daemona +Comment[fa]=شبح اخطار KDE +Comment[fi]=KDE:n huomautuspalvelin +Comment[fo]=Áminningarandi KDE's +Comment[fr]=Démon de notifications de KDE +Comment[fy]=KDE's systeemberjochtenprogramma +Comment[ga]=Deamhan Fógartha KDE +Comment[gl]=Demo de notificacións de KDE +Comment[he]=תהליך הרקע הודעות של KDE +Comment[hi]=केडीई सूचना ङेमन +Comment[hr]=KDE demon obavještavanja +Comment[hsb]=KDE-demon za zdźělenki +Comment[hu]=KDE figyelmeztető szolgáltatás +Comment[id]=Daemon pemberitahuan KDE +Comment[is]=KDE tilkynningapúkinn +Comment[it]=Demone avvisi di KDE +Comment[ja]=KDE 通知デーモン +Comment[ka]=KDE შეტყობინებების შიკრიკი +Comment[kk]=KDE құлақтандыру қызметі +Comment[ko]=KDE용 알림 서버 +Comment[lb]=KDE-Norichtendämon +Comment[lt]=KDE pranešimų tarnyba +Comment[lv]=KDE Apziņošanas Dēmons +Comment[mi]=Kaikorero KDE +Comment[mk]=KDE даемон за известувања +Comment[mn]=KDE-Сонордуулга программ +Comment[ms]=Daemon Pemberitahuan KDE +Comment[mt]=Daemon tan-notifika KDE +Comment[nb]=KDE Varslings-nisse +Comment[nds]=KDE-Dämoon för Bescheden +Comment[ne]=KDE सूचना डेइमन +Comment[nl]=KDE's systeemnotificatieprogramma +Comment[nn]=KDE-varselnisse +Comment[nso]=Daemon ya Tsebiso ya KDE +Comment[oc]=Dimoni de notificacion KDE +Comment[pa]=KDE ਟਿੱਪਣੀ ਪੇਸ਼ਕਾਰ +Comment[pl]=Demon powiadamiania KDE +Comment[pt]=Servidor de mensagens do KDE +Comment[pt_BR]=Serviço de notificação do KDE +Comment[ro]=Demon de notificare KDE +Comment[ru]=Системные сообщения KDE +Comment[rw]=Dayimoni y'Imenyesha KDE +Comment[se]=KDE dieđihanbálvá +Comment[sk]=KDE Oznamovací démon +Comment[sl]=Sistemska obvestila KDE +Comment[sq]=KDE Demoni i Njoftimit +Comment[sr]=KDE Демон за обавештавање +Comment[sr@Latn]=KDE Demon za obaveštavanje +Comment[ss]=I-daemon yekwatisa ku KDE +Comment[sv]=KDE:s underrättelsedemon +Comment[ta]=கேடிஇ அறிவிப்பு டேமன் +Comment[te]=కెడిఈ ప్రకటనల సూత్రధారి +Comment[tg]=Хабарҳои системавии KDE +Comment[th]=เดมอนการแจ้งเตือนของ KDE +Comment[tr]=KDE Bilgilendirme Programı +Comment[tt]=KDE'nıñ Kisätü Xezmäte +Comment[uk]=Демон сповіщення про нову пошту +Comment[uz]=KDE xabarnomalar xizmati +Comment[uz@cyrillic]=KDE хабарномалар хизмати +Comment[ven]=Daemon yau divhadza ya KDE +Comment[vi]=Trình nền thông báo của KDE +Comment[wa]=Démon di notifiaedje di KDE +Comment[xh]=Daemon Ulwaziso lwe KDE +Comment[zh_CN]=KDE 通告守护进程 +Comment[zh_HK]=KDE 通知伺服程式 +Comment[zh_TW]=KDE 通知服務程式 +Comment[zu]=Isaziso se-Daemon ye-KDE +Icon=knotify +ServiceTypes=KNotify +X-DCOP-ServiceType=Unique +X-KDE-StartupNotify=false diff --git a/arts/knotify/knotify.h b/arts/knotify/knotify.h new file mode 100644 index 000000000..c98be2e97 --- /dev/null +++ b/arts/knotify/knotify.h @@ -0,0 +1,111 @@ +/* + Copyright (c) 1997 Christian Esken (esken@kde.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KNOTIFY_H +#define KNOTIFY_H + +#include <qobject.h> +#include <knotifyclient.h> +#include <dcopobject.h> + +class KNotifyPrivate; +class KProcess; +class KConfig; + +class KNotify : public QObject, public DCOPObject +{ +Q_OBJECT +K_DCOP + +public: + KNotify( bool useArts ); + ~KNotify(); + + enum PlayingFinishedStatus + { + PlayedOK = 0, // success, all following mean failure + NoSoundFile, + FileAlreadyPlaying, + NoSoundSupport, + PlayerBusy, + Aborted, + Unknown = 5000 + }; + +protected: +k_dcop: + // deprecated + void notify(const QString &event, const QString &fromApp, + const QString &text, QString sound, QString file, + int present, int level); + + // deprecated + void notify(const QString &event, const QString &fromApp, + const QString &text, QString sound, QString file, + int present, int level, int winId); + + void notify(const QString &event, const QString &fromApp, + const QString &text, QString sound, QString file, + int present, int level, int winId, int eventId); + + + void reconfigure(); + void setVolume( int volume ); + void sessionReady(); // from ksmserver + +private: + bool notifyBySound(const QString &sound, const QString &appname, int eventId); + bool notifyByMessagebox(const QString &text, int level, WId winId); + bool notifyByLogfile(const QString &text, const QString &file); + bool notifyByStderr(const QString &text); + bool notifyByPassivePopup(const QString &text, const QString &appName, + KConfig* eventsFile, WId winId ); + bool notifyByExecute(const QString &command, + const QString& event, + const QString& fromApp, + const QString& text, + int winId, + int eventId ); + bool notifyByTaskbar( WId winId ); + + bool isPlaying( const QString& soundFile ) const; + + void soundFinished( int eventId, PlayingFinishedStatus reason ); + void abortFirstPlayObject(); + + WId checkWinId( const QString& appName, WId senderWinId ); + + /** + * checks if eventname is a global event (exists in config/eventsrc) + **/ + bool isGlobal(const QString &eventname); + +private slots: + void playTimeout(); + void slotPlayerProcessExited( KProcess *proc ); + void restartedArtsd(); + +private: + KNotifyPrivate* d; + void loadConfig(); +}; + + +#endif + diff --git a/arts/knotify/knotifytest.cpp b/arts/knotify/knotifytest.cpp new file mode 100644 index 000000000..9ca10cb9d --- /dev/null +++ b/arts/knotify/knotifytest.cpp @@ -0,0 +1,19 @@ +#include <string> +#include <stdio.h> +#include <kapplication.h> +#include <knotifyclient.h> + +int main(int argc, char **argv) +{ + KApplication app(argc, argv, "knotifytest"); + +// + while (1) { + char inp = getc(stdin); + + if ( inp=='q' || inp==27 ) break; + if ( inp=='1' ) KNotifyClient::userEvent( "Foo", KNotifyClient::Sound, KNotifyClient::Default, "KDE_Window_DeIconify.ogg" ); + if ( inp=='2' ) KNotifyClient::userEvent( "MessageBox Event", KNotifyClient::Messagebox ); + if ( inp=='3' ) KNotifyClient::userEvent( "Stderr Event", KNotifyClient::Stderr ); + } +} diff --git a/arts/message/Makefile.am b/arts/message/Makefile.am new file mode 100644 index 000000000..be67e4bd8 --- /dev/null +++ b/arts/message/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = $(all_includes) + +bin_PROGRAMS = artsmessage + +artsmessage_SOURCES = artsmessage.cc + +artsmessage_LDADD = ../../kdeui/libkdeui.la +artsmessage_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(KDE_MT_LDFLAGS) diff --git a/arts/message/artsmessage.cc b/arts/message/artsmessage.cc new file mode 100644 index 000000000..7a127d4a4 --- /dev/null +++ b/arts/message/artsmessage.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2001 Jeff Tranter + tranter@kde.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +------------------------------------------------------------------------ + +This application displays an error, warning, or informational message +in a dialog. It is normally used by artsd in conjunction with the -m +option. By abstracting this out of artsd, we keep it independent of +any particular graphics toolkit. + +This version uses KDE. Equivalent versions could be written using Qt, +Gnome, etc. and used instead. + +*/ + +#include <qregexp.h> + +#include <klocale.h> +#include <kglobal.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <kmessagebox.h> +#include <kcmdlineargs.h> + +// command line options +static KCmdLineOptions options[] = + { + { "e", 0,0 }, + { "error", I18N_NOOP("Display error message (default)"), 0 }, + { "w", 0, 0}, + { "warning", I18N_NOOP("Display warning message"), 0 }, + { "i", 0, 0 }, + { "info", I18N_NOOP("Display informational message"), 0 }, + { "+message", I18N_NOOP("Message string to be displayed"), 0 }, + KCmdLineLastOption // End of options. + }; + +KAboutData aboutData("artsmessage", I18N_NOOP("artsmessage"), "0.1", + I18N_NOOP("Utility to display aRts error messages"), + KAboutData::License_GPL, "(c) 2001, Jeff Tranter", 0, 0, "tranter@kde.org"); + +int main(int argc, char **argv) { + aboutData.addAuthor("Jeff Tranter", 0, "tranter@kde.org"); + KGlobal::locale()->setMainCatalogue("kdelibs"); + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + QString msg; + + // must be at least one argument + if (args->count() == 0) { + args->usage(); + } + + // build up message string from remaining arguments + for (int i = 0; i < args->count(); i++) { + if (i == 0) + msg = args->arg(i); + else + msg += QString(" ") + args->arg(i); + } + + const int notifyOptions = 0; // never activate KNotify + if (args->isSet("w")) { + KMessageBox::sorry(0, msg, i18n("Warning"), notifyOptions); + } else if (args->isSet("i")) { + QString id = msg; + id.replace(QRegExp("[\\[\\]\\s=]"), "_"); + KMessageBox::information(0, msg, i18n("Informational"), id, notifyOptions); + } else { + KMessageBox::error(0, msg, i18n("Error"), notifyOptions); + } + + return 0; +} |