author | zecke <zecke> | 2004-09-24 15:09:56 (UTC) |
---|---|---|
committer | zecke <zecke> | 2004-09-24 15:09:56 (UTC) |
commit | 8e903cd3ea735adf066e156462602987691a4c69 (patch) (side-by-side diff) | |
tree | b05fe7cc6d46cbacdc47fe3f0411100076bc8a52 | |
parent | 478b2ead47a09956cadfacb8f469fb2fdee5531c (diff) | |
download | opie-8e903cd3ea735adf066e156462602987691a4c69.zip opie-8e903cd3ea735adf066e156462602987691a4c69.tar.gz opie-8e903cd3ea735adf066e156462602987691a4c69.tar.bz2 |
-Emit Progress from the xine Engine to Global::statusMessage
-Change ThreadUtil to pass data and const char* among threads
-rw-r--r-- | noncore/multimedia/opieplayer2/lib.cpp | 18 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/lib.h | 2 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/threadutil.cpp | 17 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/threadutil.h | 6 |
4 files changed, 28 insertions, 15 deletions
diff --git a/noncore/multimedia/opieplayer2/lib.cpp b/noncore/multimedia/opieplayer2/lib.cpp index 8afb318..f1b9773 100644 --- a/noncore/multimedia/opieplayer2/lib.cpp +++ b/noncore/multimedia/opieplayer2/lib.cpp @@ -1,168 +1,168 @@ /* This file is part of the Opie Project Copyright (c) 2002 Max Reiss <harlekin@handhelds.org> Copyright (c) 2002 LJP <> Copyright (c) 2002 Holger Freyther <zecke@handhelds.org> =. .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. 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 ..}^=.= = ; 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "xinevideowidget.h" #include "frame.h" #include "lib.h" /* OPIE */ #include <opie2/odebug.h> -using namespace Opie::Core; +#include <qpe/global.h> /* QT */ #include <qtextstream.h> #include <qdir.h> #include <qgfx_qws.h> /* STD */ #include <assert.h> #include <unistd.h> typedef void (*display_xine_frame_t) (void *user_data, uint8_t* frame, int width, int height,int bytes ); extern "C" { xine_vo_driver_t* init_video_out_plugin( xine_t *xine, void* video, display_xine_frame_t, void * ); int null_is_showing_video( const xine_vo_driver_t* self ); void null_set_show_video( const xine_vo_driver_t* self, int show ); int null_is_fullscreen( const xine_vo_driver_t* self ); void null_set_fullscreen( const xine_vo_driver_t* self, int screen ); int null_is_scaling( const xine_vo_driver_t* self ); void null_set_scaling( const xine_vo_driver_t* self, int scale ); void null_set_gui_width( const xine_vo_driver_t* self, int width ); void null_set_gui_height( const xine_vo_driver_t* self, int height ); void null_set_mode( const xine_vo_driver_t* self, int depth, int rgb ); void null_set_videoGamma( const xine_vo_driver_t* self , int value ); void null_display_handler( const xine_vo_driver_t* self, display_xine_frame_t t, void* user_data ); void null_preload_decoders( xine_stream_t *stream ); } using namespace XINE; Lib::Lib( InitializationMode initMode, XineVideoWidget* widget ) { m_initialized = false; m_duringInitialization = false; m_video = false; m_wid = widget; printf("Lib"); QString configPath = QDir::homeDirPath() + "/Settings/opiexine.cf"; // get the configuration // not really OO, should be an extra class, later if ( !QFile::exists(configPath) ) { QFile f(configPath); f.open(IO_WriteOnly); QTextStream ts( &f ); ts << "misc.memcpy_method:glibc\n"; ts << "# uncomment if you experience double speed audio \n #audio.oss_sync_method:softsync\n"; ts << "codec.ffmpeg_pp_quality:3\n"; ts << "audio.num_buffers:50\n"; ts << "audio.size_buffers:4096\n"; ts << "video.num_buffers:20\n"; ts << "video.size_buffers:4096\n"; ts << "audio.out_num_audio_buf:16\n"; ts << "audio.out_size_audio_buf:8096\n"; ts << "audio.out_size_zero_buf:1024\n"; ts << "audio.passthrough_offset:0\n"; f.close(); } if ( initMode == InitializeImmediately ) { initialize(); m_initialized = true; } else start(); } void Lib::run() { odebug << "Lib::run() started" << oendl; initialize(); m_initialized = true; odebug << "Lib::run() finished" << oendl; } void Lib::initialize() { m_duringInitialization = true; m_xine = xine_new( ); QString configPath = QDir::homeDirPath() + "/Settings/opiexine.cf"; xine_config_load( m_xine, QFile::encodeName( configPath ) ); xine_init( m_xine ); // allocate oss for sound // and fb for framebuffer m_audioOutput = xine_open_audio_driver( m_xine, "oss", NULL ); m_videoOutput = ::init_video_out_plugin( m_xine, NULL, xine_display_frame, this ); m_stream = xine_stream_new (m_xine, m_audioOutput, m_videoOutput ); if (m_wid != 0 ) setWidget( m_wid ); m_queue = xine_event_new_queue (m_stream); xine_event_create_listener_thread (m_queue, xine_event_handler, this); ::null_preload_decoders( m_stream ); m_duringInitialization = false; } Lib::~Lib() { assert( isRunning() == false ); assert( m_initialized ); // free( m_config ); xine_close( m_stream ); xine_event_dispose_queue( m_queue ); xine_dispose( m_stream ); xine_exit( m_xine ); /* FIXME either free or delete but valgrind bitches against both */ //free( m_videoOutput ); //delete m_audioOutput; } void Lib::resize ( const QSize &s ) { assert( m_initialized || m_duringInitialization ); if ( s. width ( ) && s. height ( ) ) { ::null_set_gui_width( m_videoOutput, s. width() ); ::null_set_gui_height( m_videoOutput, s. height() ); @@ -201,214 +201,224 @@ int Lib::play( const QString& fileName, int startPos, int start_time ) { void Lib::stop() { assert( m_initialized ); xine_stop( m_stream ); } void Lib::pause( bool toggle ) { assert( m_initialized ); xine_set_param( m_stream, XINE_PARAM_SPEED, toggle ? XINE_SPEED_PAUSE : XINE_SPEED_NORMAL ); } int Lib::speed() const { assert( m_initialized ); return xine_get_param ( m_stream, XINE_PARAM_SPEED ); } void Lib::setSpeed( int speed ) { assert( m_initialized ); xine_set_param ( m_stream, XINE_PARAM_SPEED, speed ); } int Lib::status() const { assert( m_initialized ); return xine_get_status( m_stream ); } int Lib::currentPosition() const { assert( m_initialized ); int pos, time, length; xine_get_pos_length( m_stream, &pos, &time, &length ); return pos; } int Lib::currentTime() const { assert( m_initialized ); int pos, time, length; pos = time = length = 0; if ( xine_get_pos_length( m_stream, &pos, &time, &length ) ) return time/1000; else return 0; } int Lib::length() const { assert( m_initialized ); int pos, time, length; /* dilb: patch to solve the wrong stream length reported to the GUI*/ int iRetVal=0, iTestLoop=0; do { iRetVal = xine_get_pos_length( m_stream, &pos, &time, &length ); if (iRetVal) {/* if the function didn't return 0, then pos, time and length are valid.*/ return length/1000; } /*don't poll too much*/ usleep(100000); iTestLoop++; } while ( iTestLoop < 10 ); /* if after 1s, we still don't have any valid stream, then return -1 (this value could be used to make the stream unseekable, but it should never occur!! Mr. Murphy ? :) ) */ return -1; } bool Lib::isSeekable() const { assert( m_initialized ); return xine_get_stream_info( m_stream, XINE_STREAM_INFO_SEEKABLE ); } void Lib::seekTo( int time ) { assert( m_initialized ); xine_play( m_stream, 0, time*1000 ); } Frame Lib::currentFrame() const { assert( m_initialized ); Frame frame; return frame; }; QString Lib::metaInfo( int number) const { assert( m_initialized ); return xine_get_meta_info( m_stream, number ); } int Lib::error() const { assert( m_initialized ); return xine_get_error( m_stream ); }; void Lib::ensureInitialized() { if ( m_initialized ) return; odebug << "waiting for initialization thread to finish" << oendl; wait(); odebug << "initialization thread finished!" << oendl; } void Lib::setWidget( XineVideoWidget *widget ) { m_wid = widget; resize ( m_wid-> size ( ) ); ::null_set_mode( m_videoOutput, qt_screen->depth(), qt_screen->pixelType() ); m_wid->repaint(); } void Lib::receiveMessage( ThreadUtil::ChannelMessage *msg, SendType sendType ) { assert( sendType == ThreadUtil::Channel::OneWay ); - handleXineEvent( msg->type() ); + handleXineEvent( msg->type(), msg->data(), msg->msg() ); delete msg; } void Lib::handleXineEvent( const xine_event_t* t ) { - send( new ThreadUtil::ChannelMessage( t->type ), OneWay ); + int prog = -1; const char* name = 0; + if ( t->type == XINE_EVENT_PROGRESS ) { + xine_progress_data_t *pt = static_cast<xine_progress_data_t*>( t->data ); + prog = pt->percent; + name = pt->description; + } + + send( new ThreadUtil::ChannelMessage( t->type, prog, name ), OneWay ); } -void Lib::handleXineEvent( int type ) { +void Lib::handleXineEvent( int type, int data, const char* name ) { assert( m_initialized ); if ( type == XINE_EVENT_UI_PLAYBACK_FINISHED ) { emit stopped(); + }else if ( type == XINE_EVENT_PROGRESS ) { + QString str = name == 0 ? QString::null : QString::fromUtf8( name ); + Global::statusMessage( tr( "Progress: %1 %2" ).arg( name, data ) );; } } void Lib::setShowVideo( bool video ) { assert( m_initialized ); m_video = video; ::null_set_show_video( m_videoOutput, video ); } bool Lib::isShowingVideo() const { assert( m_initialized ); return ::null_is_showing_video( m_videoOutput ); } bool Lib::hasVideo() const { assert( m_initialized ); return xine_get_stream_info( m_stream, 18 ); } void Lib::showVideoFullScreen( bool fullScreen ) { assert( m_initialized ); ::null_set_fullscreen( m_videoOutput, fullScreen ); } bool Lib::isVideoFullScreen() const { assert( m_initialized ); return ::null_is_fullscreen( m_videoOutput ); } void Lib::setScaling( bool scale ) { assert( m_initialized ); ::null_set_scaling( m_videoOutput, scale ); } void Lib::setGamma( int value ) { assert( m_initialized ); ::null_set_videoGamma( m_videoOutput, value ); } bool Lib::isScaling() const { assert( m_initialized ); return ::null_is_scaling( m_videoOutput ); } void Lib::xine_event_handler( void* user_data, const xine_event_t* t ) { ( (Lib*)user_data)->handleXineEvent( t ); } void Lib::xine_display_frame( void* user_data, uint8_t *frame, int width, int height, int bytes ) { ( (Lib*)user_data)->drawFrame( frame, width, height, bytes ); } void Lib::drawFrame( uint8_t* frame, int width, int height, int bytes ) { assert( m_initialized ); if ( !m_video ) { return; } assert( m_wid ); m_wid-> setVideoFrame ( frame, width, height, bytes ); } diff --git a/noncore/multimedia/opieplayer2/lib.h b/noncore/multimedia/opieplayer2/lib.h index 0ff14d0..dfddc2a 100644 --- a/noncore/multimedia/opieplayer2/lib.h +++ b/noncore/multimedia/opieplayer2/lib.h @@ -78,139 +78,139 @@ namespace XINE { * Set the speed of the stream, if codec supports it * XINE_SPEED_PAUSE 0 * XINE_SPEED_SLOW_4 1 * XINE_SPEED_SLOW_2 2 * XINE_SPEED_NORMAL 4 * XINE_SPEED_FAST_2 8 *XINE_SPEED_FAST_4 16 */ void setSpeed( int speed = XINE_SPEED_PAUSE ); int status() const; int currentPosition()const; //in seconds int currentTime()const; int length() const; bool isSeekable()const; /** * Whether or not to show video output */ void setShowVideo(bool video); /** * is we show video */ bool isShowingVideo() const; /** * */ void showVideoFullScreen( bool fullScreen ); /** * */ bool isVideoFullScreen() const; /** * Get the meta info (like author etc) from the stream * XINE_META_INFO_TITLE 0 * XINE_META_INFO_COMMENT 1 * XINE_META_INFO_ARTIST 2 * XINE_META_INFO_GENRE 3 * XINE_META_INFO_ALBUM 4 * XINE_META_INFO_YEAR 5 * XINE_META_INFO_VIDEOCODEC 6 * XINE_META_INFO_AUDIOCODEC 7 * XINE_META_INFO_SYSTEMLAYER 8 * XINE_META_INFO_INPUT_PLUGIN 9 */ QString metaInfo( int number ) const; /** * */ bool isScaling() const; /** * seek to a position */ void seekTo( int time ); /** * * @return is media stream has video */ bool hasVideo() const; /** * */ void setScaling( bool ); /** * Set the Gamma value for video output * @param int the value between -100 and 100, 0 is original */ void setGamma( int ); /** * test */ Frame currentFrame() const; /** * Returns the error code * XINE_ERROR_NONE 0 * XINE_ERROR_NO_INPUT_PLUGIN 1 * XINE_ERROR_NO_DEMUXER_PLUGIN 2 * XINE_ERROR_DEMUXER_FAILED 3 */ int error() const; void ensureInitialized(); void setWidget( XineVideoWidget *widget ); signals: void stopped(); void initialized(); protected: virtual void receiveMessage( ThreadUtil::ChannelMessage *msg, SendType sendType ); virtual void run(); private: void initialize(); int m_bytes_per_pixel; bool m_initialized:1; bool m_duringInitialization:1; bool m_video:1; XineVideoWidget *m_wid; xine_t *m_xine; xine_stream_t *m_stream; xine_cfg_entry_t *m_config; xine_vo_driver_t *m_videoOutput; xine_ao_driver_t* m_audioOutput; xine_event_queue_t *m_queue; void handleXineEvent( const xine_event_t* t ); - void handleXineEvent( int type ); + void handleXineEvent( int type, int data, const char* name ); void drawFrame( uint8_t* frame, int width, int height, int bytes ); // C -> C++ bridge for the event system static void xine_event_handler( void* user_data, const xine_event_t* t); static void xine_display_frame( void* user_data, uint8_t* frame , int width, int height, int bytes ); }; }; #endif diff --git a/noncore/multimedia/opieplayer2/threadutil.cpp b/noncore/multimedia/opieplayer2/threadutil.cpp index 6ed9853..b5cac61 100644 --- a/noncore/multimedia/opieplayer2/threadutil.cpp +++ b/noncore/multimedia/opieplayer2/threadutil.cpp @@ -1,395 +1,394 @@ /* This file is part of the KDE project Copyright (C) 2002 Simon Hausmann <hausmann@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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "threadutil.h" #include <opie2/odebug.h> #include <qsocketnotifier.h> #include <pthread.h> #include <assert.h> #include <unistd.h> #include <errno.h> using namespace ThreadUtil; struct Mutex::Data { Data() { pthread_mutex_init( &mutex, 0 ); } ~Data() { pthread_mutex_destroy( &mutex ); } pthread_mutex_t mutex; }; Mutex::Mutex() : d( new Data ) { } Mutex::~Mutex() { delete d; } void Mutex::lock() { pthread_mutex_lock( &d->mutex ); } void Mutex::unlock() { pthread_mutex_unlock( &d->mutex ); } bool Mutex::tryLock() { return pthread_mutex_trylock( &d->mutex ) == 0; } bool Mutex::isLocked() { if ( !tryLock() ) return true; unlock(); return false; } struct WaitCondition::Data { Data() { int result = pthread_cond_init( &waitCondition, 0 ); assert( result == 0 ); } ~Data() { pthread_cond_destroy( &waitCondition ); } pthread_cond_t waitCondition; }; WaitCondition::WaitCondition() : d( new Data ) { } WaitCondition::~WaitCondition() { delete d; } bool WaitCondition::wait() { Mutex m; m.lock(); return wait( m ); } bool WaitCondition::wait( Mutex &mutex ) { return pthread_cond_wait( &d->waitCondition, &mutex.d->mutex ); } void WaitCondition::wakeOne() { pthread_cond_signal( &d->waitCondition ); } void WaitCondition::wakeAll() { pthread_cond_broadcast( &d->waitCondition ); } struct Thread::Data { - Data() : isRunning( false ) + Data() : isRunning( false ) {} pthread_t self; Mutex guard; bool isRunning; WaitCondition finishCondition; Thread *thr; void run() { thr->run(); } }; extern "C" { static void terminate_thread( void *arg ) { Thread::Data *data = ( Thread::Data* )arg; assert( data ); AutoLock locker( data->guard ); data->isRunning = false; data->finishCondition.wakeAll(); } static void *start_thread( void *arg ) { Thread::Data *data = ( Thread::Data* )arg; pthread_cleanup_push( terminate_thread, data ); data->isRunning = true; data->run(); pthread_cleanup_pop( true ); Thread::exit(); return 0; // never reached } } Thread::Thread() : d( new Data ) { d->thr = this; } Thread::~Thread() { assert( d->isRunning == false ); delete d; } void Thread::start() { AutoLock lock( d->guard ); if ( d->isRunning ) { - odebug << "ThreadUtil::Thread::start() called for running thread." << oendl; + odebug << "ThreadUtil::Thread::start() called for running thread." << oendl; return; } pthread_attr_t attributes; pthread_attr_init( &attributes ); pthread_attr_setscope( &attributes, PTHREAD_SCOPE_SYSTEM ); int err = pthread_create( &d->self, &attributes, start_thread, ( void* )d ); if ( err != 0 ) { - odebug << "ThreadUtil::Thread::start() : can't create thread: " << strerror( err ) << "" << oendl; + odebug << "ThreadUtil::Thread::start() : can't create thread: " << strerror( err ) << "" << oendl; pthread_attr_destroy( &attributes ); return; } pthread_attr_destroy( &attributes ); } void Thread::terminate() { AutoLock lock( d->guard ); if ( !d->isRunning ) return; pthread_cancel( d->self ); } bool Thread::wait() { AutoLock lock( d->guard ); if ( !d->isRunning ) return true; return d->finishCondition.wait( d->guard ); } bool Thread::isRunning() const { AutoLock lock( d->guard ); return d->isRunning; } void Thread::exit() { pthread_exit( 0 ); } OnewayNotifier::OnewayNotifier() { int fds[ 2 ]; pipe( fds ); m_readFd = fds[ 0 ]; m_writeFd = fds[ 1 ]; m_notifier = new QSocketNotifier( m_readFd, QSocketNotifier::Read ); connect( m_notifier, SIGNAL( activated(int) ), this, SLOT( wakeUp() ) ); } OnewayNotifier::~OnewayNotifier() { delete m_notifier; ::close( m_readFd ); ::close( m_writeFd ); } void OnewayNotifier::notify() { const char c = 42; ::write( m_writeFd, &c, 1 ); } void OnewayNotifier::wakeUp() { char c = 0; if ( ::read( m_readFd, &c, 1 ) != 1 ) return; emit awake(); } -ChannelMessage::ChannelMessage( int type ) - : m_type( type ), m_isCall( false ), m_replied( false ), - m_inEventHandler( false ) -{ -} +ChannelMessage::ChannelMessage( int type, int data, const char* msg ) + : m_type( type ), m_data( data ), m_msg( msg ), + m_isCall( false ), m_replied( false ), m_inEventHandler( false ) +{} ChannelMessage::~ChannelMessage() { if ( m_guard.isLocked() ) m_guard.unlock(); } void ChannelMessage::reply() { if ( !m_isCall ) { - odebug << "ChannelMessage::reply() - can't reply oneway message!" << oendl; + odebug << "ChannelMessage::reply() - can't reply oneway message!" << oendl; return; } if ( m_inEventHandler ) { m_replied = true; return; } m_condition.wakeOne(); m_guard.unlock(); } struct Channel::Private { Private() { ownerThread = pthread_self(); } pthread_t ownerThread; }; Channel::Channel( QObject *parent, const char *name ) : QObject( parent, name ), d( new Private ) { connect( &m_notifier, SIGNAL( awake() ), this, SLOT( deliver() ) ); } Channel::~Channel() { delete d; } void Channel::send( ChannelMessage *message, SendType type ) { if ( type == WaitForReply ) { message->m_guard.lock(); message->m_isCall = true; } m_pendingMessagesGuard.lock(); m_pendingMessages << MsgEnvelope( type, message ); m_pendingMessagesGuard.unlock(); if ( d->ownerThread == pthread_self() ) { assert( type != WaitForReply ); deliver(); } else m_notifier.notify(); //QThread::postEvent( this, new QCustomEvent( QEvent::User, envelope ) ); if ( type == WaitForReply ) { message->m_condition.wait( message->m_guard ); message->m_guard.unlock(); } } void Channel::deliver() { AutoLock lock( m_pendingMessagesGuard ); while ( !m_pendingMessages.isEmpty() ) { MsgEnvelope envelope = m_pendingMessages.first(); m_pendingMessages.remove( m_pendingMessages.begin() ); m_pendingMessagesGuard.unlock(); deliverOne( envelope ); m_pendingMessagesGuard.lock(); } } void Channel::deliverOne( const MsgEnvelope &envelope ) { ChannelMessage *msg = envelope.msg; assert( msg ); if ( envelope.type == WaitForReply ) { msg->m_guard.lock(); msg->m_inEventHandler = true; } receiveMessage( msg, envelope.type ); if ( envelope.type == WaitForReply ) { msg->m_inEventHandler = false; if ( msg->m_replied ) { msg->m_condition.wakeOne(); // this is a bit tricky. we unlock only when we reply. // reply() does an unlock as well. msg->m_guard.unlock(); } } } /* vim: et sw=4 ts=4 */ diff --git a/noncore/multimedia/opieplayer2/threadutil.h b/noncore/multimedia/opieplayer2/threadutil.h index 2e83d3a..f97a18b 100644 --- a/noncore/multimedia/opieplayer2/threadutil.h +++ b/noncore/multimedia/opieplayer2/threadutil.h @@ -8,192 +8,196 @@ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef THREADUTIL_H #define THREADUTIL_H #include <qvaluelist.h> #include <qobject.h> #include <qguardedptr.h> class QSocketNotifier; namespace ThreadUtil { class Mutex { friend class WaitCondition; public: Mutex(); ~Mutex(); void lock(); void unlock(); bool tryLock(); bool isLocked(); private: struct Data; Data *d; Mutex( const Mutex & ); Mutex &operator=( const Mutex & ); }; class AutoLock { public: AutoLock( Mutex &mutex ) : m_mutex( mutex ) { m_mutex.lock(); } ~AutoLock() { m_mutex.unlock(); } Mutex *operator &() const { return &m_mutex; } private: Mutex &m_mutex; }; class WaitCondition { public: WaitCondition(); ~WaitCondition(); bool wait(); bool wait( Mutex &mutex ); void wakeOne(); void wakeAll(); private: struct Data; Data *d; WaitCondition( const WaitCondition & ); WaitCondition &operator=( const WaitCondition & ); }; class Thread { public: struct Data; friend struct Data; Thread(); virtual ~Thread(); void start(); void terminate(); bool wait(); bool isRunning() const; static void exit(); protected: virtual void run() = 0; private: Data *d; }; class OnewayNotifier : public QObject { Q_OBJECT public: OnewayNotifier(); ~OnewayNotifier(); void notify(); signals: void awake(); private slots: void wakeUp(); private: int m_readFd; int m_writeFd; QSocketNotifier *m_notifier; }; class Channel; class ChannelMessage { friend class Channel; public: - ChannelMessage( int type = -1 ); + ChannelMessage( int type = -1, int data = -1, const char* msg = 0 ); virtual ~ChannelMessage(); int type() const { return m_type; } + int data() const { return m_data; } + const char* msg()const { return m_msg; } void reply(); private: ChannelMessage( const ChannelMessage & ); ChannelMessage &operator=( const ChannelMessage ); int m_type; + int m_data; + const char *m_msg; bool m_isCall : 1; bool m_replied : 1; bool m_inEventHandler : 1; Mutex m_guard; WaitCondition m_condition; }; class Channel : public QObject { Q_OBJECT public: enum SendType { OneWay, WaitForReply }; Channel( QObject *parent = 0, const char *name = 0 ); virtual ~Channel(); void send( ChannelMessage *message, SendType type ); protected: virtual void receiveMessage( ChannelMessage *message, SendType type ) = 0; private slots: void deliver(); private: OnewayNotifier m_notifier; struct MsgEnvelope { MsgEnvelope() : type( OneWay ), msg( 0 ) {} MsgEnvelope( SendType _type , ChannelMessage *_msg ) : type( _type ), msg( _msg ) {} SendType type; ChannelMessage *msg; }; void deliverOne( const MsgEnvelope &envelope ); typedef QValueList<MsgEnvelope> MsgEnvelopeList; MsgEnvelopeList m_pendingMessages; Mutex m_pendingMessagesGuard; struct Private; Private *d; }; } #endif // THREADUTIL_H /* vim: et sw=4 ts=4 */ |