summaryrefslogtreecommitdiffstats
path: root/src/part
diff options
context:
space:
mode:
Diffstat (limited to 'src/part')
-rw-r--r--src/part/SConscript12
-rw-r--r--src/part/part.cpp83
-rw-r--r--src/part/part.h38
-rw-r--r--src/part/toolbar.cpp44
-rw-r--r--src/part/toolbar.h18
-rw-r--r--src/part/videoWindow.cpp192
-rw-r--r--src/part/videoWindow.h94
-rw-r--r--src/part/xineEngine.cpp345
8 files changed, 826 insertions, 0 deletions
diff --git a/src/part/SConscript b/src/part/SConscript
new file mode 100644
index 0000000..c2bce67
--- /dev/null
+++ b/src/part/SConscript
@@ -0,0 +1,12 @@
+# Copyright 2005 Max Howell <max.howell@methylblue.com>
+
+Import( "*" )
+myenv=env.Copy()
+
+## Additional paths for compiling the source files
+## Always add '../' (top-level directory) because moc makes code that needs it
+KDEaddpaths( ['./', '../', '../../'], myenv )
+
+KDEaddlibs( ['qt-mt', 'kdecore', 'kdeui', 'kparts', 'xine'], myenv )
+
+KDEshlib( "libcodeine", Split( "part.cpp xineEngine.cpp videoWindow.cpp toolbar.cpp ../mxcl.library.cpp" ), myenv )
diff --git a/src/part/part.cpp b/src/part/part.cpp
new file mode 100644
index 0000000..20d1577
--- /dev/null
+++ b/src/part/part.cpp
@@ -0,0 +1,83 @@
+// Author: Max Howell <max.howell@methylblue.com>, (C) 2005
+// Copyright: See COPYING file that comes with this distribution
+
+#include "codeine.h"
+#include "debug.h"
+#include <kaboutdata.h>
+#include <kparts/genericfactory.h>
+#include "part.h"
+#include <qtimer.h>
+#include "toolbar.h"
+#include "videoWindow.h"
+
+#include <kaction.h>
+#include <qslider.h>
+
+namespace Codeine
+{
+ typedef KParts::GenericFactory<Codeine::Part> Factory;
+}
+
+
+K_EXPORT_COMPONENT_FACTORY( libcodeine, Codeine::Factory )
+
+
+namespace Codeine
+{
+ Part::Part( QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList& )
+ : ReadOnlyPart( parent, name )
+ , m_statusBarExtension( new KParts::StatusBarExtension( this ) )
+ {
+ setInstance( Factory::instance() );
+ setWidget( new VideoWindow( parentWidget, widgetName ) );
+
+ if( !videoWindow()->init() )
+ //FIXME this will terminate the host, eg Konqueror
+ Debug::fatal() << "Couldn't init xine!\n";
+
+ KAction *play = new KToggleAction( i18n("Play"), "player_play", Qt::Key_Space, videoWindow(), SLOT(togglePlay()), actionCollection(), "play" );
+ KAction *mute = new KToggleAction( i18n("Mute"), "player_mute", Qt::Key_M, videoWindow(), SLOT(toggleMute()), actionCollection(), "mute" );
+ KToolBar *toolBar = new MouseOverToolBar( widget() );
+ play->plug( toolBar );
+ mute->plug( toolBar );
+ m_slider = new QSlider( Qt::Horizontal, toolBar, "slider" );
+ m_slider->setMaxValue( 65535 );
+ toolBar->setStretchableWidget( m_slider );
+ toolBar->addSeparator(); //FIXME ugly
+
+ QObject *o = (QObject*)statusBar();
+ connect( videoWindow(), SIGNAL(statusMessage( const QString& )), o, SLOT(message( const QString& )) );
+ connect( videoWindow(), SIGNAL(titleChanged( const QString& )), o, SLOT(message( const QString& )) ); //FIXME
+ }
+
+ bool
+ Part::openURL( const KURL &url )
+ {
+ //FIXME nasty, we'd rather not do this way
+ killTimers();
+ startTimer( 100 );
+
+ return videoWindow()->play( m_url = url );
+ }
+
+ bool
+ Part::closeURL()
+ {
+ m_url = KURL();
+ videoWindow()->eject();
+ return true;
+ }
+
+ KAboutData*
+ Part::createAboutData()
+ {
+ // generic factory expects this on the heap
+ return new KAboutData( APP_NAME, PRETTY_NAME, APP_VERSION );
+ }
+
+ void
+ Part::timerEvent( QTimerEvent* )
+ {
+ m_slider->setValue( videoWindow()->position() );
+ }
+}
diff --git a/src/part/part.h b/src/part/part.h
new file mode 100644
index 0000000..30467ac
--- /dev/null
+++ b/src/part/part.h
@@ -0,0 +1,38 @@
+// Author: Max Howell <max.howell@methylblue.com>, (C) 2005
+// Copyright: See COPYING file that comes with this distribution
+
+#ifndef CODEINE_PART_H
+#define CODEINE_PART_H
+
+#include <kparts/statusbarextension.h>
+#include <kparts/part.h>
+#include <kurl.h>
+
+class KAboutData;
+class QSlider;
+
+
+namespace Codeine
+{
+ class Part : public KParts::ReadOnlyPart
+ {
+ public:
+ Part( QWidget*, const char*, QObject*, const char*, const QStringList& );
+
+ virtual bool openFile() { return false; } //pure virtual in base class
+ virtual bool openURL( const KURL& );
+ virtual bool closeURL();
+
+ static KAboutData *createAboutData();
+
+ private:
+ KParts::StatusBarExtension *m_statusBarExtension;
+ QSlider *m_slider;
+
+ KStatusBar *statusBar() { return m_statusBarExtension->statusBar(); }
+
+ virtual void timerEvent( QTimerEvent* );
+ };
+}
+
+#endif
diff --git a/src/part/toolbar.cpp b/src/part/toolbar.cpp
new file mode 100644
index 0000000..8939074
--- /dev/null
+++ b/src/part/toolbar.cpp
@@ -0,0 +1,44 @@
+// (C) 2005 Max Howell (max.howell@methylblue.com)
+// See COPYING file for licensing information
+
+#include <kpushbutton.h>
+#include <qapplication.h>
+#include <qevent.h>
+#include "toolbar.h"
+
+
+MouseOverToolBar::MouseOverToolBar( QWidget *parent )
+ : KToolBar( parent )
+{
+ parent->installEventFilter( this );
+ move( 0, 0 ); //TODO necessary?
+ hide();
+
+ setPalette( QApplication::palette() ); //videoWindow palette has a black background
+}
+
+bool
+MouseOverToolBar::eventFilter( QObject *o, QEvent *e )
+{
+ Q_ASSERT( o == parent() );
+
+ switch( e->type() )
+ {
+ case QEvent::Resize:
+ resize( static_cast<QResizeEvent*>(e)->size().width(), sizeHint().height() );
+ break;
+
+ case QEvent::Enter:
+ show();
+ break;
+
+ case QEvent::Leave:
+ hide();
+ break;
+
+ default:
+ ;
+ }
+
+ return false;
+} \ No newline at end of file
diff --git a/src/part/toolbar.h b/src/part/toolbar.h
new file mode 100644
index 0000000..cd189d4
--- /dev/null
+++ b/src/part/toolbar.h
@@ -0,0 +1,18 @@
+// (C) 2005 Max Howell (max.howell@methylblue.com)
+// See COPYING file for licensing information
+
+#ifndef CODEINE_TOOLBAR_H
+#define CODEINE_TOOLBAR_H
+
+#include <ktoolbar.h>
+
+
+class MouseOverToolBar : public KToolBar
+{
+ virtual bool eventFilter( QObject*, QEvent* );
+
+public:
+ MouseOverToolBar( QWidget *parent );
+};
+
+#endif
diff --git a/src/part/videoWindow.cpp b/src/part/videoWindow.cpp
new file mode 100644
index 0000000..d798b36
--- /dev/null
+++ b/src/part/videoWindow.cpp
@@ -0,0 +1,192 @@
+// (C) 2005 Max Howell (max.howell@methylblue.com)
+// See COPYING file for licensing information
+
+#define CODEINE_DEBUG_PREFIX "videoWindow"
+
+#include <cstdlib>
+#include "debug.h"
+#include <qapplication.h> //sendEvent()
+#include <qcursor.h>
+#include <qevent.h>
+#include "videoWindow.h"
+#include <X11/Xlib.h> //TODO this breaks compile for lots of people due to excessive macro content
+#include <xine.h> //x11_visual_t
+
+
+namespace Codeine {
+
+
+VideoWindow *VideoWindow::s_instance = 0;
+
+
+namespace X
+{
+ Display *d;
+ int s, w;
+}
+
+
+VideoWindow::VideoWindow( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+ , m_osd( 0 )
+ , m_stream( 0 )
+ , m_eventQueue( 0 )
+ , m_videoPort( 0 )
+ , m_audioPort( 0 )
+ , m_xine( 0 )
+ , m_displayRatio( 1 )
+{
+ s_instance = this;
+
+ // with this Konqueror would crash on exit
+ // without this we may be unstable!
+ //XInitThreads();
+
+ show();
+
+ setWFlags( Qt::WNoAutoErase );
+ setMouseTracking( true );
+ setAcceptDrops( true );
+ setUpdatesEnabled( false ); //to stop Qt drawing over us
+ setPaletteBackgroundColor( Qt::black );
+
+ X::d = XOpenDisplay( std::getenv("DISPLAY") );
+ X::s = DefaultScreen( X::d );
+ X::w = winId();
+
+ XLockDisplay( X::d );
+ XSelectInput( X::d, X::w, ExposureMask );
+
+ {
+ using X::d; using X::s;
+
+ //these are Xlib macros
+ double w = DisplayWidth( d, s ) * 1000 / DisplayWidthMM( d, s );
+ double h = DisplayHeight( d, s ) * 1000 / DisplayHeightMM( d, s );
+
+ m_displayRatio = w / h;
+ }
+
+ XUnlockDisplay( X::d );
+
+ connect( &m_timer, SIGNAL(timeout()), SLOT(hideCursor()) );
+}
+
+VideoWindow::~VideoWindow()
+{
+ DEBUG_BLOCK
+
+ if( m_osd ) xine_osd_free( m_osd );
+ if( m_stream ) xine_close( m_stream );
+ if( m_eventQueue ) xine_event_dispose_queue( m_eventQueue );
+ if( m_stream ) xine_dispose( m_stream );
+ if( m_videoPort ) xine_close_video_driver( m_xine, m_videoPort );
+ if( m_audioPort ) xine_close_audio_driver( m_xine, m_audioPort );
+ if( m_xine ) xine_exit( m_xine );
+
+ XCloseDisplay( X::d );
+}
+
+void*
+VideoWindow::x11Visual() const
+{
+ x11_visual_t* visual = new x11_visual_t;
+
+ visual->display = X::d;
+ visual->screen = X::s;
+ visual->d = X::w;
+ visual->dest_size_cb = &VideoWindow::destSizeCallBack;
+ visual->frame_output_cb = &VideoWindow::frameOutputCallBack;
+ visual->user_data = (void*)this;
+
+ return visual;
+}
+
+void
+VideoWindow::destSizeCallBack(
+ void* p, int /*video_width*/, int /*video_height*/,
+ double /*video_aspect*/, int* dest_width,
+ int* dest_height, double* dest_aspect )
+{
+ if( !p )
+ return;
+
+ #define vw static_cast<VideoWindow*>(p)
+
+ *dest_width = vw->width();
+ *dest_height = vw->height();
+ *dest_aspect = vw->m_displayRatio;
+}
+
+void
+VideoWindow::frameOutputCallBack(
+ void* p, int video_width, int video_height, double video_aspect,
+ int* dest_x, int* dest_y, int* dest_width, int* dest_height,
+ double* dest_aspect, int* win_x, int* win_y )
+{
+ if( !p )
+ return;
+
+ *dest_x = 0;
+ *dest_y = 0 ;
+ *dest_width = vw->width();
+ *dest_height = vw->height();
+ *win_x = vw->x();
+ *win_y = vw->y();
+ *dest_aspect = vw->m_displayRatio;
+
+ // correct size with video aspect
+ // TODO what's this about?
+ if( video_aspect >= vw->m_displayRatio )
+ video_width = int( double(video_width * video_aspect / vw->m_displayRatio + 0.5) );
+ else
+ video_height = int( double(video_height * vw->m_displayRatio / video_aspect) + 0.5 );
+
+ #undef vw
+}
+
+bool
+VideoWindow::event( QEvent *e )
+{
+ switch( e->type() )
+ {
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonPress:
+ unsetCursor();
+ m_timer.start( CURSOR_HIDE_TIMEOUT, true );
+ break;
+
+ case QEvent::Close:
+ case QEvent::Hide:
+ xine_stop( m_stream );
+ break;
+
+ case QEvent::Leave:
+ m_timer.stop();
+ break;
+
+ default:
+ ;
+ }
+
+ return QWidget::event( e );
+}
+
+bool
+VideoWindow::x11Event( XEvent *e )
+{
+ if( e->type == Expose && e->xexpose.count == 0 ) {
+ xine_gui_send_vo_data( m_stream, XINE_GUI_SEND_EXPOSE_EVENT, e );
+ return true;
+ }
+
+ return false;
+}
+
+void
+VideoWindow::hideCursor()
+{
+ setCursor( Qt::BlankCursor );
+}
+
+} //namespace Codeine
diff --git a/src/part/videoWindow.h b/src/part/videoWindow.h
new file mode 100644
index 0000000..7db72ab
--- /dev/null
+++ b/src/part/videoWindow.h
@@ -0,0 +1,94 @@
+// (C) 2005 Max Howell (max.howell@methylblue.com)
+// See COPYING file for licensing information
+
+#ifndef CODEINE_VIDEO_WINDOW_H
+#define CODEINE_VIDEO_WINDOW_H
+
+#include "../codeine.h"
+#include <qtimer.h>
+#include <qwidget.h>
+#include <kurl.h>
+
+typedef struct xine_s xine_t;
+typedef struct xine_stream_s xine_stream_t;
+typedef struct xine_video_port_s xine_video_port_t;
+typedef struct xine_audio_port_s xine_audio_port_t;
+typedef struct xine_event_queue_s xine_event_queue_t;
+typedef struct xine_post_s xine_post_t;
+typedef struct xine_osd_s xine_osd_t;
+
+
+namespace Codeine
+{
+ class VideoWindow : public QWidget
+ {
+ Q_OBJECT
+
+ static VideoWindow *s_instance;
+ static const uint CURSOR_HIDE_TIMEOUT = 2000;
+
+ friend VideoWindow* const videoWindow();
+
+ public:
+ VideoWindow( QWidget *parent, const char *name );
+ ~VideoWindow();
+
+ bool init();
+
+ bool play( KURL );
+ void eject();
+
+ int position();
+
+ signals:
+ void statusMessage( const QString& );
+ void titleChanged( const QString& );
+
+ private:
+ /// @see xineEngine.cpp
+ #ifdef HAVE_XINE_H
+ static void xineEventListener( void*, const xine_event_t* );
+ #endif
+
+ void showErrorMessage(); //TODO don't use this, just show delayed message
+
+ virtual void customEvent( QCustomEvent* );
+ virtual bool x11Event( XEvent* );
+ virtual bool event( QEvent* );
+
+ xine_osd_t *m_osd;
+ xine_stream_t *m_stream;
+ xine_event_queue_t *m_eventQueue;
+ xine_video_port_t *m_videoPort;
+ xine_audio_port_t *m_audioPort;
+ xine_t *m_xine;
+
+ KURL m_url;
+
+ private:
+ void *x11Visual() const;
+
+ static void destSizeCallBack( void*, int, int, double, int*, int*, double* );
+ static void frameOutputCallBack( void*, int, int, double, int*, int*, int*, int*, double*, int*, int* );
+
+ double m_displayRatio;
+ QTimer m_timer;
+
+ public slots:
+ void togglePlay();
+ void toggleMute();
+
+ private slots:
+ void hideCursor();
+
+ private:
+ /// prevent compiler generated functions
+ VideoWindow( const VideoWindow& );
+ VideoWindow &operator=( const VideoWindow& );
+ bool operator==( const VideoWindow& );
+ };
+
+ inline VideoWindow* const videoWindow() { return VideoWindow::s_instance; }
+}
+
+#endif
diff --git a/src/part/xineEngine.cpp b/src/part/xineEngine.cpp
new file mode 100644
index 0000000..2365f83
--- /dev/null
+++ b/src/part/xineEngine.cpp
@@ -0,0 +1,345 @@
+// (C) 2005 Max Howell (max.howell@methylblue.com)
+// See COPYING file for licensing information
+
+#define CODEINE_DEBUG_PREFIX "engine"
+
+#include "debug.h"
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include "mxcl.library.h"
+#include <qapplication.h> //::sendEvent()
+#include <qdatetime.h> //::play()
+#include <qdir.h> //QDir::homeDir()
+#include <xine.h>
+#include "videoWindow.h"
+
+
+namespace Codeine {
+
+
+bool
+VideoWindow::init()
+{
+ mxcl::WaitCursor allocateOnStack;
+
+ debug() << "xine_new()\n";
+ m_xine = xine_new();
+ if( !m_xine )
+ return false;
+
+ debug() << "xine_config_load()\n";
+ xine_config_load( m_xine, QFile::encodeName( QDir::homeDirPath() + "/.xine/config" ) );
+
+ debug() << "xine_init()\n";
+ xine_init( m_xine );
+
+ debug() << "xine_open_video_driver()\n";
+ m_videoPort = xine_open_video_driver( m_xine, "auto", XINE_VISUAL_TYPE_X11, x11Visual() );
+
+ debug() << "xine_open_audio_driver()\n";
+ m_audioPort = xine_open_audio_driver( m_xine, "auto", NULL );
+
+ debug() << "xine_stream_new()\n";
+ m_stream = xine_stream_new( m_xine, m_audioPort, m_videoPort );
+ if( !m_stream )
+ return false;
+
+ if( !m_audioPort )
+ MessageBox::error( i18n("xine was unable to initialize any audio-drivers.") );
+ if( !m_videoPort )
+ MessageBox::error( i18n("xine was unable to initialize any video-drivers.") );
+
+ debug() << "xine_osd_new()\n";
+ m_osd = xine_osd_new( m_stream, 10, 10, 1000, 18 * 6 + 10 );
+ if( m_osd ) {
+ xine_osd_set_font( m_osd, "sans", 18 );
+ xine_osd_set_text_palette( m_osd, XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1 );
+ }
+
+ debug() << "xine_event_create_listener_thread()\n";
+ xine_event_create_listener_thread(
+ m_eventQueue = xine_event_new_queue( m_stream ),
+ &VideoWindow::xineEventListener, (void*)this );
+
+ { /// set save directory
+ xine_cfg_entry_t config;
+
+ if( xine_config_lookup_entry( m_xine, "misc.save_dir", &config ) ) {
+ const QCString dir = KGlobalSettings::desktopPath().local8Bit();
+ config.str_value = qstrdup( dir );
+ xine_config_update_entry( m_xine, &config );
+ }
+ }
+
+ return true;
+}
+
+bool
+VideoWindow::play( KURL url )
+{
+ DEBUG_BLOCK
+
+ m_url = url;
+
+ mxcl::WaitCursor allocateOnStack;
+
+ //TODO make sensible
+ if( url.protocol() == "http" ) {
+ /// automatically save http streams to Desktop folder
+
+ const QString fileName = url.filename();
+
+ QString
+ u = url.url();
+ u += "#save:";
+ u += url.host();
+ u += " [";
+ u += QDate::currentDate().toString();
+ u += ']';
+ u += fileName.mid( fileName.findRev( '.' ) + 1 ).lower();
+
+ url = u;
+ }
+
+ debug() << "About to load..\n";
+ if( xine_open( m_stream, url.url().local8Bit() ) )
+ {
+ debug() << "About to play..\n";
+ if( xine_play( m_stream, 0, 0 ) )
+ return true;
+ }
+
+ showErrorMessage();
+ return false;
+}
+
+void
+VideoWindow::togglePlay()
+{
+ if( xine_get_param( m_stream, XINE_PARAM_SPEED ) ) {
+ xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE );
+ xine_set_param( m_stream, XINE_PARAM_AUDIO_CLOSE_DEVICE, 1);
+ }
+ else
+ xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL );
+}
+
+void
+VideoWindow::toggleMute()
+{
+ bool const muted = xine_get_param( m_stream, XINE_PARAM_AUDIO_MUTE );
+ xine_set_param( m_stream, XINE_PARAM_AUDIO_MUTE, !muted );
+}
+
+void
+VideoWindow::eject()
+{
+ m_url = KURL();
+
+ xine_stop( m_stream );
+}
+
+int
+VideoWindow::position()
+{
+ int pos = 0, time = 0, length = 0;
+ xine_get_pos_length( m_stream, &pos, &time, &length );
+
+ return pos;
+}
+
+void
+VideoWindow::showErrorMessage()
+{
+ const QString filename = m_url.fileName();
+
+ debug() << "xine_get_error()\n";
+
+ // NOTE these error messages are somewhat customised
+ // relative to the main application
+ // This is because when embedded in some other application
+ // the error messages have no context, so we must say that we are a video player!
+
+ switch( xine_get_error( m_stream ) )
+ {
+ case XINE_ERROR_NO_INPUT_PLUGIN:
+ MessageBox::sorry( i18n("The Codeine video player could not find an input plugin for '%1'.").arg( filename ) );
+ break;
+ case XINE_ERROR_NO_DEMUX_PLUGIN:
+ MessageBox::sorry( i18n("The Codeine video player could not find a demux plugin for '%1'.").arg( filename ) );
+ break;
+ case XINE_ERROR_DEMUX_FAILED:
+ MessageBox::sorry( i18n("The Codeine video player failed to demux '%1'; please check your xine installation.").arg( filename ) );
+ break;
+ case XINE_ERROR_INPUT_FAILED:
+ case XINE_ERROR_MALFORMED_MRL:
+ case XINE_ERROR_NONE:
+ MessageBox::sorry( i18n("The Codeine video player reports an internal error; please check your xine installation.") );
+ break;
+ }
+}
+
+void
+VideoWindow::customEvent( QCustomEvent *e )
+{
+ switch( e->type() - 2000 ) {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+//FIXME emit stateChanged( Engine::TrackEnded );
+ break;
+
+ case 1000:
+ #define message static_cast<QString*>(e->data())
+ emit statusMessage( *message );
+ delete message;
+ break;
+
+ case 1001:
+ MessageBox::sorry( (*message).arg( "FIXME" ) ); //FIXME
+ delete message;
+ break;
+
+ case 1002:
+ emit titleChanged( *message );
+ delete message;
+ break;
+ #undef message
+
+ default:
+ ;
+ }
+}
+
+void
+VideoWindow::xineEventListener( void *p, const xine_event_t* xineEvent )
+{
+ if( !p )
+ return;
+
+ #define engine static_cast<VideoWindow*>(p)
+
+ switch( xineEvent->type ) {
+ case XINE_EVENT_MRL_REFERENCE:
+ {
+ mxcl::WaitCursor allocateOnStack;
+ const char *mrl = ((xine_mrl_reference_data_t*)xineEvent->data)->mrl;
+
+ debug() << "XINE_EVENT_MRL_REFERENCE: " << mrl << endl;
+
+ if( xine_open( engine->m_stream, mrl ) )
+ xine_play( engine->m_stream, 0, 0 );
+
+ break;
+ }
+
+ case XINE_EVENT_UI_NUM_BUTTONS: debug() << "XINE_EVENT_UI_NUM_BUTTONS\n"; break;
+ case XINE_EVENT_DROPPED_FRAMES: debug() << "XINE_EVENT_DROPPED_FRAMES\n"; break;
+
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ case XINE_EVENT_FRAME_FORMAT_CHANGE:
+ case XINE_EVENT_UI_CHANNELS_CHANGED:
+ {
+ QCustomEvent *ce;
+ ce = new QCustomEvent( 2000 + xineEvent->type );
+ ce->setData( const_cast<xine_event_t*>(xineEvent) );
+ QApplication::postEvent( engine, ce );
+ break;
+ }
+
+ case XINE_EVENT_UI_SET_TITLE:
+ QApplication::postEvent( engine, new QCustomEvent(
+ QEvent::Type(3002),
+ new QString( QString::fromUtf8( static_cast<xine_ui_data_t*>(xineEvent->data)->str ) ) ) );
+ break;
+
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t* pd = (xine_progress_data_t*)xineEvent->data;
+
+ QString
+ msg = "%1 %2%";
+ msg = msg.arg( QString::fromUtf8( pd->description ) )
+ .arg( KGlobal::locale()->formatNumber( pd->percent, 0 ) );
+
+ QApplication::postEvent( engine, new QCustomEvent( QEvent::Type(3000), new QString( msg ) ) );
+ break;
+ }
+ case XINE_EVENT_UI_MESSAGE:
+ {
+ debug() << "Message received from xine\n";
+
+ xine_ui_message_data_t *data = (xine_ui_message_data_t *)xineEvent->data;
+ QString message;
+
+ switch( data->type ) {
+ case XINE_MSG_NO_ERROR:
+ {
+ //series of \0 separated strings, terminated with a \0\0
+ char str[2000];
+ char *p = str;
+ for( char *msg = data->messages; !(*msg == '\0' && *(msg+1) == '\0'); ++msg, ++p )
+ *p = *msg == '\0' ? '\n' : *msg;
+ *p = '\0';
+
+ debug() << str << endl;
+
+ break;
+ }
+
+ case XINE_MSG_ENCRYPTED_SOURCE:
+ message = i18n("The source is encrypted and can not be decrypted."); goto param;
+ case XINE_MSG_UNKNOWN_HOST:
+ message = i18n("The host is unknown for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_UNKNOWN_DEVICE:
+ message = i18n("The device name you specified seems invalid."); goto param;
+ case XINE_MSG_NETWORK_UNREACHABLE:
+ message = i18n("The network appears unreachable."); goto param;
+ case XINE_MSG_AUDIO_OUT_UNAVAILABLE:
+ message = i18n("Audio output unavailable; the device is busy."); goto param;
+ case XINE_MSG_CONNECTION_REFUSED:
+ message = i18n("The connection was refused for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_FILE_NOT_FOUND:
+ message = i18n("xine could not find the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_PERMISSION_ERROR:
+ message = i18n("Access was denied for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_READ_ERROR:
+ message = i18n("The source cannot be read for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_LIBRARY_LOAD_ERROR:
+ message = i18n("A problem occurred while loading a library or decoder."); goto param;
+
+ case XINE_MSG_GENERAL_WARNING:
+ case XINE_MSG_SECURITY:
+ default:
+
+ if(data->explanation)
+ {
+ message += "<b>";
+ message += QString::fromUtf8( (char*) data + data->explanation );
+ message += "</b>";
+ }
+ else break; //if no explanation then why bother!
+
+ //FALL THROUGH
+
+ param:
+
+ message.prepend( "<p>" );
+ message += "<p>";
+
+ if(data->parameters)
+ {
+ message += "xine says: <i>";
+ message += QString::fromUtf8( (char*) data + data->parameters);
+ message += "</i>";
+ }
+ else message += i18n("Sorry, no additional information is available.");
+
+ QApplication::postEvent( engine, new QCustomEvent(QEvent::Type(3001), new QString(message)) );
+ }
+
+ } //case
+ } //switch
+
+ #undef engine
+}
+
+} //namespace Codeine