[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    =?utf-8?q?=5Bkaffeine=5D_/=3A_switch_from_=28lib-=29xine_to_=28l?=
From:       Christoph Pfister <christophpfister () gmail ! com>
Date:       2011-04-30 17:01:28
Message-ID: 20110430170128.3D132A60A4 () git ! kde ! org
[Download RAW message or body]

Git commit e31652b06cc46dde488804b09205487d8036114f by Christoph Pfister.
Committed on 30/04/2011 at 18:48.
Pushed by pfister into branch 'master'.

switch from (lib-)xine to (lib-)vlc

- many issues (esp. crashes) vanish / are easier to fix
- likely you need the 'full' vlc package (with X11 plugins)
- this commit introduces introduces various regressions ;-)
- big picture problems with libvlc:
  - dvd navigation (likely solved with libvlc 1.2 once it's released)
  - VDPAU
- make MediaWidget more state-orientated, i.e. separate between
 - functions, which modify the state (e.g. a signal from the backend)
 - functions, which rely on the state (e.g. ui updates)

M  +1    -2    CMakeLists.txt     
M  +2    -2    README     
M  +2    -12   src/CMakeLists.txt     
A  +608  -0    src/backend-vlc/vlcmediawidget.cpp         [License: GPL (v2+)]
A  +77   -0    src/backend-vlc/vlcmediawidget.h         [License: GPL (v2+)]
A  +96   -0    src/backend-vlc/vlcmediawidget_p.h         [License: GPL (v2+)]
D  +0    -1008 src/backend-xine/xineapplication.cpp     
D  +0    -138  src/backend-xine/xineapplication.h     
D  +0    -303  src/backend-xine/xinecommands.cpp     
D  +0    -357  src/backend-xine/xinecommands.h     
D  +0    -1042 src/backend-xine/xinemediawidget.cpp     
D  +0    -186  src/backend-xine/xinemediawidget.h     
D  +0    -55   src/backend-xine/xinemediawidget_p.h     
M  +16   -6    src/dbusobjects.cpp     
M  +4    -0    src/dbusobjects.h     
M  +125  -24   src/dvb/dvbliveview.cpp     
M  +18   -3    src/dvb/dvbliveview_p.h     
M  +2    -2    src/dvb/dvbtab.cpp     
M  +19   -3    src/mainwindow.cpp     
M  +2    -1    src/mainwindow.h     
M  +543  -572  src/mediawidget.cpp     
M  +89   -53   src/mediawidget.h     
M  +0    -31   src/mediawidget_p.h     

http://commits.kde.org/kaffeine/e31652b06cc46dde488804b09205487d8036114f

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3a1cf39..1bc7c4e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,9 +2,8 @@ project(kaffeine)
 
 find_package(KDE4 REQUIRED)
 find_package(X11 REQUIRED)
-find_package(Xine REQUIRED)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_BINARY_DIR} \
                ${KDE4_INCLUDES}
-                    ${X11_INCLUDE_DIR} ${X11_Xscreensaver_INCLUDE_PATH} \
${XINE_INCLUDE_DIR}) +                    ${X11_Xscreensaver_INCLUDE_PATH})
 add_definitions(${KDE4_DEFINITIONS})
 
 if(STRICT_BUILD)
diff --git a/README b/README
index 6ec6cdc..3952f8a 100644
--- a/README
+++ b/README
@@ -5,9 +5,9 @@ Installing Kaffeine
 The following development headers are needed (recommended versions):
 * Qt >= 4.6
 * KDE >= 4.4
-* xine-lib
-* libXss
+* libvlc >= 1.1.1
 * libX11
+* libXss
 
 For the translations you need:
 * gettext
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2c00837..d50d9f0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,5 @@
 set(kaffeine_SRCS
-    backend-xine/xinecommands.cpp
-    backend-xine/xinemediawidget.cpp
+    backend-vlc/vlcmediawidget.cpp
     playlist/playlistmodel.cpp
     playlist/playlisttab.cpp
     configuration.cpp
@@ -37,20 +36,11 @@ if(HAVE_DVB)
       dvb/dvbtransponder.cpp)
 endif(HAVE_DVB)
 
-set(kaffeinexbu_SRCS
-    backend-xine/xineapplication.cpp
-    backend-xine/xinecommands.cpp
-    log.cpp)
-
 configure_file(config-kaffeine.h.cmake ${CMAKE_BINARY_DIR}/config-kaffeine.h)
 
 kde4_add_executable(kaffeine ${kaffeinedvb_SRCS} ${kaffeine_SRCS})
 target_link_libraries(kaffeine ${QT_QTSQL_LIBRARY} ${KDE4_KFILE_LIBS} \
                ${KDE4_KIO_LIBS}
-                      ${KDE4_SOLID_LIBS} ${X11_Xscreensaver_LIB})
+                      ${KDE4_SOLID_LIBS} ${X11_Xscreensaver_LIB} vlc)
 install(TARGETS kaffeine ${INSTALL_TARGETS_DEFAULT_ARGS})
 install(FILES scanfile.dvb DESTINATION ${DATA_INSTALL_DIR}/kaffeine)
 install(PROGRAMS kaffeine.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
-
-kde4_add_executable(kaffeine-xbu ${kaffeinexbu_SRCS})
-target_link_libraries(kaffeine-xbu ${X11_X11_LIB} ${XINE_LIBRARY} \
                ${KDE4_KDEUI_LIBS})
-install(TARGETS kaffeine-xbu ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/src/backend-vlc/vlcmediawidget.cpp b/src/backend-vlc/vlcmediawidget.cpp
new file mode 100644
index 0000000..a86a304
--- /dev/null
+++ b/src/backend-vlc/vlcmediawidget.cpp
@@ -0,0 +1,608 @@
+/*
+ * vlcmediawidget.cpp
+ *
+ * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
+ *
+ * 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.
+ */
+
+#include "vlcmediawidget.h"
+#include "vlcmediawidget_p.h"
+
+#include <QCoreApplication>
+#include <vlc/vlc.h>
+#include "../log.h"
+
+AbstractMediaWidget::AbstractMediaWidget(QWidget *parent) : QWidget(parent)
+{
+}
+
+AbstractMediaWidget::~AbstractMediaWidget()
+{
+}
+
+AbstractMediaWidget *AbstractMediaWidget::createVlcMediaWidget(QWidget *parent)
+{
+	AbstractMediaWidget *mediaWidget = VlcMediaWidget::createVlcMediaWidget(parent);
+
+	if (mediaWidget == NULL) {
+		mediaWidget = new AbstractMediaWidget(parent);
+	}
+
+	return mediaWidget;
+}
+
+void AbstractMediaWidget::setMuted(bool muted)
+{
+	Q_UNUSED(muted)
+}
+
+void AbstractMediaWidget::setVolume(int volume)
+{
+	Q_UNUSED(volume)
+}
+
+void AbstractMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
+{
+	Q_UNUSED(aspectRatio)
+}
+
+void AbstractMediaWidget::setDeinterlacing(bool deinterlacing)
+{
+	Q_UNUSED(deinterlacing)
+}
+
+void AbstractMediaWidget::play(MediaWidget::Source source, const KUrl &url,
+	const KUrl &subtitleUrl)
+{
+	Q_UNUSED(source)
+	Q_UNUSED(url)
+	Q_UNUSED(subtitleUrl)
+}
+
+void AbstractMediaWidget::stop()
+{
+	emit updatePlaybackStatus(MediaWidget::Idle);
+}
+
+void AbstractMediaWidget::setPaused(bool paused)
+{
+	Q_UNUSED(paused)
+}
+
+void AbstractMediaWidget::seek(int time)
+{
+	Q_UNUSED(time)
+}
+
+void AbstractMediaWidget::setCurrentAudioChannel(int currentAudioChannel)
+{
+	Q_UNUSED(currentAudioChannel)
+}
+
+void AbstractMediaWidget::setCurrentSubtitle(int currentSubtitle)
+{
+	Q_UNUSED(currentSubtitle)
+}
+
+void AbstractMediaWidget::setExternalSubtitle(const KUrl &subtitleUrl)
+{
+	Q_UNUSED(subtitleUrl)
+}
+
+void AbstractMediaWidget::setCurrentTitle(int currentTitle)
+{
+	Q_UNUSED(currentTitle)
+}
+
+void AbstractMediaWidget::setCurrentChapter(int currentChapter)
+{
+	Q_UNUSED(currentChapter)
+}
+
+void AbstractMediaWidget::setCurrentAngle(int currentAngle)
+{
+	Q_UNUSED(currentAngle)
+}
+
+bool AbstractMediaWidget::jumpToPreviousChapter()
+{
+	return false;
+}
+
+bool AbstractMediaWidget::jumpToNextChapter()
+{
+	return false;
+}
+
+void AbstractMediaWidget::toggleMenu()
+{
+}
+
+VlcMediaWidget::VlcMediaWidget(QWidget *parent) : AbstractMediaWidget(parent), \
vlcInstance(NULL), +	vlcMediaPlayer(NULL)
+{
+}
+
+bool VlcMediaWidget::init()
+{
+	const char *arguments[] = { "--no-video-title-show" };
+	vlcInstance = libvlc_new(sizeof(arguments) / sizeof(arguments[0]), arguments);
+
+	if (vlcInstance == NULL) {
+		Log("VlcMediaWidget::init: cannot create vlc instance") << libvlc_errmsg();
+		return false;
+	}
+
+	vlcMediaPlayer = libvlc_media_player_new(vlcInstance);
+
+	if (vlcMediaPlayer == NULL) {
+		Log("VlcMediaWidget::init: cannot create vlc media player") << libvlc_errmsg();
+		return false;
+	}
+
+	libvlc_event_manager_t *eventManager = \
libvlc_media_player_event_manager(vlcMediaPlayer); +	libvlc_event_e eventTypes[] = { \
libvlc_MediaPlayerEncounteredError, +		libvlc_MediaPlayerEndReached, \
libvlc_MediaPlayerLengthChanged, +		libvlc_MediaPlayerSeekableChanged, \
libvlc_MediaPlayerStopped, +		libvlc_MediaPlayerTimeChanged };
+
+	for (uint i = 0; i < (sizeof(eventTypes) / sizeof(eventTypes[0])); ++i) {
+		if (libvlc_event_attach(eventManager, eventTypes[i], eventHandler, this) != 0) {
+			Log("VlcMediaWidget::init: cannot attach event handler") << eventTypes[i];
+			return false;
+		}
+	}
+
+	libvlc_media_player_set_xwindow(vlcMediaPlayer, winId());
+	setAttribute(Qt::WA_NativeWindow);
+	setAttribute(Qt::WA_PaintOnScreen);
+	return true;
+}
+
+VlcMediaWidget::~VlcMediaWidget()
+{
+	if (vlcMediaPlayer != NULL) {
+		libvlc_media_player_release(vlcMediaPlayer);
+	}
+
+	if (vlcInstance != NULL) {
+		libvlc_release(vlcInstance);
+	}
+}
+
+VlcMediaWidget *VlcMediaWidget::createVlcMediaWidget(QWidget *parent)
+{
+	QScopedPointer<VlcMediaWidget> vlcMediaWidget(new VlcMediaWidget(parent));
+
+	if (!vlcMediaWidget->init()) {
+		return NULL;
+	}
+
+	return vlcMediaWidget.take();
+}
+
+void VlcMediaWidget::setMuted(bool muted)
+{
+	libvlc_audio_set_mute(vlcMediaPlayer, muted);
+}
+
+void VlcMediaWidget::setVolume(int volume)
+{
+	// 0 <= volume <= 200
+	if (libvlc_audio_set_volume(vlcMediaPlayer, volume) != 0) {
+		Log("VlcMediaWidget::setVolume: cannot set volume") << volume;
+	}
+}
+
+void VlcMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
+{
+	// "", "1:1", "4:3", "5:4", 16:9", "16:10", "221:100", "235:100", "239:100"
+	const char *vlcAspectRatio = "";
+	int vlcScaleFactor = 1;
+
+	switch (aspectRatio) {
+	case MediaWidget::AspectRatioAuto:
+		break;
+	case MediaWidget::AspectRatio4_3:
+		vlcAspectRatio = "4:3";
+		break;
+	case MediaWidget::AspectRatio16_9:
+		vlcAspectRatio = "16:9";
+		break;
+	case MediaWidget::AspectRatioWidget:
+		// zero = adjust video to window
+		vlcScaleFactor = 0;
+		break;
+	}
+
+	libvlc_video_set_aspect_ratio(vlcMediaPlayer, vlcAspectRatio);
+	libvlc_video_set_scale(vlcMediaPlayer, vlcScaleFactor);
+}
+
+void VlcMediaWidget::setDeinterlacing(bool deinterlacing)
+{
+	// "", "blend", "bob", "discard", "ivtc", "linear",
+	// "mean", "phosphor", "x", "yadif", "yadif2x"
+	const char *vlcDeinterlaceMode = "";
+
+	if (deinterlacing) {
+		vlcDeinterlaceMode = "yadif";
+	}
+
+	libvlc_video_set_deinterlace(vlcMediaPlayer, vlcDeinterlaceMode);
+}
+
+void VlcMediaWidget::play(MediaWidget::Source source, const KUrl &url, const KUrl \
&subtitleUrl) +{
+	QByteArray encodedUrl = url.toEncoded();
+
+	switch (source) {
+	case MediaWidget::Playlist:
+	case MediaWidget::Dvb:
+	case MediaWidget::DvbTimeShift:
+		// FIXME how to treat ".iso" files?
+		break;
+	case MediaWidget::AudioCd:
+		encodedUrl.replace(0, 4, "cdda");
+		break;
+	case MediaWidget::VideoCd:
+		encodedUrl.replace(0, 4, "vcd");
+		break;
+	case MediaWidget::Dvd:
+		encodedUrl.replace(0, 4, "dvd");
+		break;
+	}
+
+	libvlc_media_t *vlcMedia = libvlc_media_new_location(vlcInstance, \
encodedUrl.constData()); +
+	if (vlcMedia == NULL) {
+		Log("VlcMediaWidget::play: cannot create media") << url.prettyUrl();
+		stop();
+		return;
+	}
+
+	libvlc_event_manager_t *eventManager = libvlc_media_event_manager(vlcMedia);
+	libvlc_event_e eventTypes[] = { libvlc_MediaMetaChanged };
+
+	for (uint i = 0; i < (sizeof(eventTypes) / sizeof(eventTypes[0])); ++i) {
+		if (libvlc_event_attach(eventManager, eventTypes[i], eventHandler, this) != 0) {
+			Log("VlcMediaWidget::play: cannot attach event handler") << eventTypes[i];
+		}
+	}
+
+	libvlc_media_player_set_media(vlcMediaPlayer, vlcMedia);
+	libvlc_media_release(vlcMedia);
+	setDirtyFlags(UpdatePlaybackStatus | UpdateTotalTime | UpdateCurrentTime | \
UpdateSeekable | +		UpdateMetadata | UpdateAudioChannels | UpdateSubtitles | \
UpdateTitles | +		UpdateChapters | UpdateAngles);
+
+	if (!subtitleUrl.isEmpty()) {
+		if (libvlc_video_set_subtitle_file(vlcMediaPlayer,
+		    subtitleUrl.toEncoded().constData()) == 0) {
+			Log("VlcMediaWidget::play: cannot set subtitle file") <<
+				subtitleUrl.prettyUrl();
+		}
+	}
+
+	if (libvlc_media_player_play(vlcMediaPlayer) != 0) {
+		Log("VlcMediaWidget::play: cannot play media") << url.prettyUrl();
+		stop();
+		return;
+	}
+}
+
+void VlcMediaWidget::stop()
+{
+	libvlc_media_player_stop(vlcMediaPlayer);
+	setDirtyFlags(UpdatePlaybackStatus | UpdateTotalTime | UpdateCurrentTime | \
UpdateSeekable | +		UpdateMetadata | UpdateAudioChannels | UpdateSubtitles | \
UpdateTitles | +		UpdateChapters | UpdateAngles);
+}
+
+void VlcMediaWidget::setPaused(bool paused)
+{
+	libvlc_media_player_set_pause(vlcMediaPlayer, paused);
+	addDirtyFlags(UpdatePlaybackStatus);
+}
+
+void VlcMediaWidget::seek(int time)
+{
+	libvlc_media_player_set_time(vlcMediaPlayer, time);
+}
+
+void VlcMediaWidget::setCurrentAudioChannel(int currentAudioChannel)
+{
+	libvlc_audio_set_track(vlcMediaPlayer, currentAudioChannel);
+}
+
+void VlcMediaWidget::setCurrentSubtitle(int currentSubtitle)
+{
+	libvlc_video_set_spu(vlcMediaPlayer, currentSubtitle);
+}
+
+void VlcMediaWidget::setExternalSubtitle(const KUrl &subtitleUrl)
+{
+	if (libvlc_video_set_subtitle_file(vlcMediaPlayer,
+	    subtitleUrl.toEncoded().constData()) == 0) {
+		Log("VlcMediaWidget::setExternalSubtitle: cannot set subtitle file") <<
+			subtitleUrl.prettyUrl();
+	}
+}
+
+void VlcMediaWidget::setCurrentTitle(int currentTitle)
+{
+	libvlc_media_player_set_title(vlcMediaPlayer, currentTitle);
+}
+
+void VlcMediaWidget::setCurrentChapter(int currentChapter)
+{
+	libvlc_media_player_set_chapter(vlcMediaPlayer, currentChapter);
+}
+
+void VlcMediaWidget::setCurrentAngle(int currentAngle)
+{
+	Q_UNUSED(currentAngle)
+	// FIXME
+}
+
+bool VlcMediaWidget::jumpToPreviousChapter()
+{
+	int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
+	int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
+	libvlc_media_player_previous_chapter(vlcMediaPlayer);
+
+	if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) ||
+	    (libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) {
+		return true;
+	}
+
+	return false;
+}
+
+bool VlcMediaWidget::jumpToNextChapter()
+{
+	int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
+	int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
+	libvlc_media_player_next_chapter(vlcMediaPlayer);
+
+	if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) ||
+	    (libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) {
+		return true;
+	}
+
+	return false;
+}
+
+void VlcMediaWidget::toggleMenu()
+{
+	// FIXME
+}
+
+QSize VlcMediaWidget::sizeHint() const
+{
+	// FIXME
+	return QWidget::sizeHint();
+}
+
+void VlcMediaWidget::customEvent(QEvent *event)
+{
+	Q_UNUSED(event)
+
+	while (true) {
+		uint oldDirtyFlags = dirtyFlags;
+		uint lowestDirtyFlag = (oldDirtyFlags & (~(oldDirtyFlags - 1)));
+		uint newDirtyFlags = (oldDirtyFlags & (~lowestDirtyFlag));
+
+		if (oldDirtyFlags == newDirtyFlags) {
+			break;
+		}
+
+		if (!dirtyFlags.testAndSetRelaxed(oldDirtyFlags, newDirtyFlags)) {
+			continue;
+		}
+
+		switch (lowestDirtyFlag) {
+		case PlaybackFinished:
+			emit playbackFinished();
+			break;
+		case UpdatePlaybackStatus: {
+			MediaWidget::PlaybackStatus playbackStatus = MediaWidget::Playing;
+
+			switch (libvlc_media_player_get_state(vlcMediaPlayer)) {
+			case libvlc_NothingSpecial:
+			case libvlc_Stopped:
+			case libvlc_Ended:
+			case libvlc_Error:
+				playbackStatus = MediaWidget::Idle;
+				break;
+			case libvlc_Opening:
+			case libvlc_Buffering:
+			case libvlc_Playing:
+				playbackStatus = MediaWidget::Playing;
+				break;
+			case libvlc_Paused:
+				playbackStatus = MediaWidget::Paused;
+				break;
+			}
+
+			emit updatePlaybackStatus(playbackStatus);
+			break;
+		    }
+		case UpdateTotalTime:
+			emit updateTotalTime(libvlc_media_player_get_length(vlcMediaPlayer));
+			break;
+		case UpdateCurrentTime:
+			emit updateCurrentTime(libvlc_media_player_get_time(vlcMediaPlayer));
+			break;
+		case UpdateSeekable:
+			emit updateSeekable(libvlc_media_player_is_seekable(vlcMediaPlayer));
+			break;
+		case UpdateMetadata: {
+			QMap<MediaWidget::MetadataType, QString> metadata;
+			libvlc_media_t *media = libvlc_media_player_get_media(vlcMediaPlayer);
+
+			if (media != NULL) {
+				metadata.insert(MediaWidget::Title, QString::fromUtf8(
+					libvlc_media_get_meta(media, libvlc_meta_Title)));
+				metadata.insert(MediaWidget::Artist, QString::fromUtf8(
+					libvlc_media_get_meta(media, libvlc_meta_Artist)));
+				metadata.insert(MediaWidget::Album, QString::fromUtf8(
+					libvlc_media_get_meta(media, libvlc_meta_Album)));
+				metadata.insert(MediaWidget::TrackNumber, QString::fromUtf8(
+					libvlc_media_get_meta(media, libvlc_meta_TrackNumber)));
+			}
+
+			emit updateMetadata(metadata);
+			break;
+		    }
+		case UpdateAudioChannels: {
+			QStringList audioChannels;
+			libvlc_track_description_t *track =
+				libvlc_audio_get_track_description(vlcMediaPlayer);
+
+			while (track != NULL) {
+				QString audioChannel = QString::fromUtf8(track->psz_name);
+
+				if (audioChannel.isEmpty()) {
+					audioChannel = QString::number(audioChannels.size() + 1);
+				}
+
+				audioChannels.append(audioChannel);
+				track = track->p_next;
+			}
+
+			Log("VlcMediaWidget::customEvent: number of audio channels") << \
audioChannels.size(); +			Log("XXX:") << \
libvlc_audio_get_track_count(vlcMediaPlayer); +			int currentAudioChannel = \
libvlc_audio_get_track(vlcMediaPlayer); +			emit updateAudioChannels(audioChannels, \
currentAudioChannel); +			break;
+		    }
+		case UpdateSubtitles: {
+			QStringList subtitles;
+			libvlc_track_description_t *track =
+				libvlc_video_get_spu_description(vlcMediaPlayer);
+
+			while (track != NULL) {
+				QString subtitle = QString::fromUtf8(track->psz_name);
+
+				if (subtitle.isEmpty()) {
+					subtitle = QString::number(subtitles.size() + 1);
+				}
+
+				subtitles.append(subtitle);
+				track = track->p_next;
+			}
+
+			int currentSubtitle = libvlc_video_get_spu(vlcMediaPlayer);
+			emit updateSubtitles(subtitles, currentSubtitle);
+			break;
+		    }
+		case UpdateTitles: {
+			int titleCount = libvlc_media_player_get_title_count(vlcMediaPlayer);
+			int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
+			emit updateTitles(titleCount, currentTitle);
+			break;
+		    }
+		case UpdateChapters: {
+			int chapterCount = libvlc_media_player_get_chapter_count(vlcMediaPlayer);
+			int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
+			emit updateChapters(chapterCount, currentChapter);
+			break;
+		    }
+		case UpdateAngles: {
+			// FIXME
+			break;
+		    }
+		case UpdateDvdPlayback: {
+			// FIXME
+			break;
+		    }
+		case UpdateVideoSize: {
+			// FIXME
+			break;
+		    }
+		default:
+			Log("VlcMediaWidget::customEvent: unknown dirty flag") << lowestDirtyFlag;
+			break;
+		}
+	}
+}
+
+void VlcMediaWidget::eventHandler(const libvlc_event_t *event, void *instance)
+{
+	uint changedDirtyFlags = 0;
+
+	switch (event->type) {
+	case libvlc_MediaMetaChanged:
+		Log("VlcMediaWidget::eventHandler: called");
+		changedDirtyFlags = (UpdateMetadata | UpdateAudioChannels | UpdateSubtitles |
+			UpdateTitles | UpdateChapters | UpdateAngles);
+		break;
+	case libvlc_MediaPlayerEncounteredError:
+		changedDirtyFlags = UpdatePlaybackStatus;
+		break;
+	case libvlc_MediaPlayerEndReached:
+		changedDirtyFlags = (PlaybackFinished | UpdatePlaybackStatus);
+		break;
+	case libvlc_MediaPlayerLengthChanged:
+		changedDirtyFlags = UpdateTotalTime;
+		break;
+	case libvlc_MediaPlayerSeekableChanged:
+		changedDirtyFlags = UpdateSeekable;
+		break;
+	case libvlc_MediaPlayerStopped:
+		changedDirtyFlags = UpdatePlaybackStatus;
+		break;
+	case libvlc_MediaPlayerTimeChanged:
+		changedDirtyFlags = UpdateCurrentTime;
+		break;
+	}
+
+	if (changedDirtyFlags != 0) {
+		reinterpret_cast<VlcMediaWidget *>(instance)->addDirtyFlags(changedDirtyFlags);
+	} else {
+		Log("VlcMediaWidget::eventHandler: unknown event type") << event->type;
+	}
+}
+
+void VlcMediaWidget::addDirtyFlags(uint changedDirtyFlags)
+{
+	while (true) {
+		uint oldDirtyFlags = dirtyFlags;
+		uint newDirtyFlags = (oldDirtyFlags | changedDirtyFlags);
+
+		if (oldDirtyFlags == newDirtyFlags) {
+			break;
+		}
+
+		if (!dirtyFlags.testAndSetRelaxed(oldDirtyFlags, newDirtyFlags)) {
+			continue;
+		}
+
+		if (oldDirtyFlags == 0) {
+			QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+		}
+
+		break;
+	}
+}
+
+void VlcMediaWidget::setDirtyFlags(uint newDirtyFlags)
+{
+	if (dirtyFlags.fetchAndStoreRelaxed(newDirtyFlags) == 0) {
+		QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+	}
+}
diff --git a/src/backend-vlc/vlcmediawidget.h b/src/backend-vlc/vlcmediawidget.h
new file mode 100644
index 0000000..b85b3da
--- /dev/null
+++ b/src/backend-vlc/vlcmediawidget.h
@@ -0,0 +1,77 @@
+/*
+ * vlcmediawidget.h
+ *
+ * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef VLCMEDIAWIDGET_H
+#define VLCMEDIAWIDGET_H
+
+#include "../mediawidget.h"
+
+class AbstractMediaWidget : public QWidget
+{
+	Q_OBJECT
+protected:
+	explicit AbstractMediaWidget(QWidget *parent);
+
+public:
+	~AbstractMediaWidget();
+
+	static AbstractMediaWidget *createVlcMediaWidget(QWidget *parent);
+
+	virtual void setMuted(bool muted);
+	virtual void setVolume(int volume); // [0 - 100]
+	virtual void setAspectRatio(MediaWidget::AspectRatio aspectRatio);
+	virtual void setDeinterlacing(bool deinterlacing);
+
+	// it is guaranteed that updatePlaybackStatus() will
+	// be emitted after calling play() or stop()
+	virtual void play(MediaWidget::Source source, const KUrl &url, const KUrl \
&subtitleUrl); +	virtual void stop();
+
+	virtual void setPaused(bool paused);
+	virtual void seek(int time);
+	virtual void setCurrentAudioChannel(int currentAudioChannel);
+	virtual void setCurrentSubtitle(int currentSubtitle);
+	virtual void setExternalSubtitle(const KUrl &subtitleUrl);
+	virtual void setCurrentTitle(int currentTitle); // first title = 0
+	virtual void setCurrentChapter(int currentChapter); // first chapter = 0
+	virtual void setCurrentAngle(int currentAngle); // first angle = 0
+	virtual bool jumpToPreviousChapter();
+	virtual bool jumpToNextChapter();
+	virtual void toggleMenu();
+
+signals:
+	void playbackFinished();
+	void updatePlaybackStatus(MediaWidget::PlaybackStatus playbackStatus);
+	void updateTotalTime(int totalTime); // milliseconds
+	void updateCurrentTime(int currentTime); // milliseconds
+	void updateMetadata(const QMap<MediaWidget::MetadataType, QString> &metadata);
+	void updateSeekable(bool seekable);
+	// first audio channel = 0
+	void updateAudioChannels(const QStringList &audioChannels, int \
currentAudioChannel); +	// first subtitle = 0
+	void updateSubtitles(const QStringList &subtitles, int currentSubtitle);
+	void updateTitles(int titleCount, int currentTitle);
+	void updateChapters(int chapterCount, int currentChapter);
+	void updateAngles(int angleCount, int currentAngle);
+	void updateDvdPlayback(bool playingDvd);
+	void updateVideoSize();
+};
+
+#endif /* VLCMEDIAWIDGET_H */
diff --git a/src/backend-vlc/vlcmediawidget_p.h b/src/backend-vlc/vlcmediawidget_p.h
new file mode 100644
index 0000000..3dd3e20
--- /dev/null
+++ b/src/backend-vlc/vlcmediawidget_p.h
@@ -0,0 +1,96 @@
+/*
+ * vlcmediawidget_p.h
+ *
+ * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef VLCMEDIAWIDGET_P_H
+#define VLCMEDIAWIDGET_P_H
+
+#include "vlcmediawidget.h"
+
+class libvlc_event_t;
+class libvlc_instance_t;
+class libvlc_media_player_t;
+
+class VlcMediaWidget : public AbstractMediaWidget
+{
+private:
+	explicit VlcMediaWidget(QWidget *parent);
+	bool init();
+
+public:
+	~VlcMediaWidget();
+
+	static VlcMediaWidget *createVlcMediaWidget(QWidget *parent);
+
+	void setMuted(bool muted);
+	void setVolume(int volume); // [0 - 100]
+	void setAspectRatio(MediaWidget::AspectRatio aspectRatio);
+	void setDeinterlacing(bool deinterlacing);
+
+	// it is guaranteed that updatePlaybackStatus() will
+	// be emitted after calling play() or stop()
+	void play(MediaWidget::Source source, const KUrl &url, const KUrl &subtitleUrl);
+	void stop();
+
+	void setPaused(bool paused);
+	void seek(int time);
+	void setCurrentAudioChannel(int currentAudioChannel);
+	void setCurrentSubtitle(int currentSubtitle);
+	void setExternalSubtitle(const KUrl &subtitleUrl);
+	void setCurrentTitle(int currentTitle); // first title = 0
+	void setCurrentChapter(int currentChapter); // first chapter = 0
+	void setCurrentAngle(int currentAngle); // first angle = 0
+	bool jumpToPreviousChapter();
+	bool jumpToNextChapter();
+	void toggleMenu();
+
+	QSize sizeHint() const;
+
+protected:
+	void customEvent(QEvent *event);
+
+private:
+	static void eventHandler(const libvlc_event_t *event, void *instance);
+
+	enum DirtyFlag
+	{
+		PlaybackFinished = (1 << 0),
+		UpdatePlaybackStatus = (1 << 1),
+		UpdateTotalTime = (1 << 2),
+		UpdateCurrentTime = (1 << 3),
+		UpdateSeekable = (1 << 4),
+		UpdateMetadata = (1 << 5),
+		UpdateAudioChannels = (1 << 6),
+		UpdateSubtitles = (1 << 7),
+		UpdateTitles = (1 << 8),
+		UpdateChapters = (1 << 9),
+		UpdateAngles = (1 << 10),
+		UpdateDvdPlayback = (1 << 11),
+		UpdateVideoSize = (1 << 12)
+	};
+
+	void addDirtyFlags(uint changedDirtyFlags);
+	void setDirtyFlags(uint newDirtyFlags);
+
+	libvlc_instance_t *vlcInstance;
+	libvlc_media_player_t *vlcMediaPlayer;
+	QAtomicInt dirtyFlags;
+};
+
+#endif /* VLCMEDIAWIDGET_P_H */
diff --git a/src/backend-xine/xineapplication.cpp \
b/src/backend-xine/xineapplication.cpp deleted file mode 100644
index 0e5fb3d..0000000
--- a/src/backend-xine/xineapplication.cpp
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * xineapplication.cpp
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#include "xineapplication.h"
-
-#include <QFile>
-#include <QVector>
-#include <KAboutData>
-#include <KApplication>
-#include <KCmdLineArgs>
-#include <KStandardDirs>
-#include <X11/Xlib.h>
-#include "../log.h"
-#include "xinecommands.h"
-
-class XineParent : public XineParentMarshaller
-{
-public:
-	XineParent(int fd, QObject *parent) : writer(fd, parent)
-	{
-		XineParentMarshaller::writer = &writer;
-	}
-
-	~XineParent() { }
-
-private:
-	XinePipeWriter writer;
-};
-
-XineObject::XineObject() : engine(NULL), audioOutput(NULL), videoOutput(NULL), \
                stream(NULL),
-	eventQueue(NULL), widgetSize(0), overrideTitleCount(0), overrideCurrentTitle(0),
-	dirtyFlags(NotReady), aspectRatio(XineAspectRatioAuto), videoSize(0)
-{
-	reader = new XinePipeReader(3, this);
-	parentProcess = new XineParent(4, this);
-	positionTimer.setInterval(500);
-	connect(&positionTimer, SIGNAL(timeout()), this, SLOT(updatePosition()));
-}
-
-XineObject::~XineObject()
-{
-	if (eventQueue != NULL) {
-		xine_event_dispose_queue(eventQueue);
-	}
-
-	if (stream != NULL) {
-		xine_dispose(stream);
-	}
-
-	if (deinterlacer != NULL) {
-		xine_post_dispose(engine, deinterlacer);
-	}
-
-	if (visualization != NULL) {
-		xine_post_dispose(engine, visualization);
-	}
-
-	if (videoOutput != NULL) {
-		xine_close_video_driver(engine, videoOutput);
-	}
-
-	if (audioOutput != NULL) {
-		xine_close_audio_driver(engine, audioOutput);
-	}
-
-	if (engine != NULL) {
-		xine_config_save(engine, QFile::encodeName(
-			KStandardDirs::locateLocal("data", "kaffeine/xine-config")).constData());
-		xine_exit(engine);
-	}
-
-	delete reader;
-	delete parentProcess;
-}
-
-const char *XineObject::version()
-{
-	return xine_get_version_string();
-}
-
-void XineObject::readyRead()
-{
-	reader->readyRead();
-
-	while (true) {
-		int command = reader->nextCommand();
-
-		switch (command) {
-		case -1:
-			return;
-		case XineCommands::Quit:
-			kapp->quit();
-			dirtyFlags |= Quit;
-			return;
-		case XineCommands::Init: {
-			quint64 windowId = reader->readLongLong();
-
-			if (reader->isValid()) {
-				init(windowId);
-			}
-
-			break;
-		    }
-		case XineCommands::Resize: {
-			quint16 width = reader->readShort();
-			quint16 height = reader->readShort();
-
-			if (reader->isValid()) {
-				widgetSize = ((width << 16) | height);
-			}
-
-			break;
-		    }
-		case XineCommands::SetMuted: {
-			bool muted_ = reader->readBool();
-
-			if (reader->isValid()) {
-				muted = muted_;
-				dirtyFlags |= SetMuted;
-			}
-
-			break;
-		    }
-		case XineCommands::SetVolume: {
-			quint8 volume_ = reader->readChar();
-
-			if (reader->isValid()) {
-				volume = volume_;
-				dirtyFlags |= SetVolume;
-			}
-
-			break;
-		    }
-		case XineCommands::SetAspectRatio: {
-			qint8 aspectRatio_ = reader->readChar();
-
-			if (reader->isValid()) {
-				aspectRatio = aspectRatio_;
-				dirtyFlags |= SetAspectRatio;
-			}
-
-			break;
-		    }
-		case XineCommands::SetDeinterlacing: {
-			bool deinterlacing_ = reader->readBool();
-
-			if (reader->isValid()) {
-				deinterlacing = deinterlacing_;
-				dirtyFlags |= SetDeinterlacing;
-			}
-
-			break;
-		    }
-		case XineCommands::PlayUrl: {
-			quint32 sequenceNumber_ = reader->readInt();
-			QByteArray encodedUrl_ = reader->readByteArray();
-			
-			if (reader->isValid()) {
-				sequenceNumber = sequenceNumber_;
-				encodedUrl = encodedUrl_;
-				dirtyFlags &= ~(PlayStream | SetPaused | Seek | Repaint |
-						MouseMoved | MousePressed |
-						SetCurrentAudioChannel | SetCurrentSubtitle |
-						ToggleMenu);
-				dirtyFlags |= OpenStream;
-			}
-
-			break;
-		    }
-		case XineCommands::SetPaused: {
-			bool paused_ = reader->readBool();
-
-			if (reader->isValid()) {
-				paused = paused_;
-				dirtyFlags |= SetPaused;
-			}
-
-			break;
-		    }
-		case XineCommands::Seek: {
-			qint32 seekTime_ = reader->readInt();
-
-			if (reader->isValid()) {
-				seekTime = seekTime_;
-				dirtyFlags |= Seek;
-			}
-
-			break;
-		    }
-		case XineCommands::Repaint:
-			dirtyFlags |= Repaint;
-			break;
-		case XineCommands::MouseMoved: {
-			quint16 x = reader->readShort();
-			quint16 y = reader->readShort();
-
-			if (reader->isValid()) {
-				mouseMovePosition = ((x << 16) | y);
-				dirtyFlags |= MouseMoved;
-			}
-
-			break;
-		    }
-		case XineCommands::MousePressed: {
-			quint16 x = reader->readShort();
-			quint16 y = reader->readShort();
-
-			if (reader->isValid()) {
-				mousePressPosition = ((x << 16) | y);
-				dirtyFlags |= MousePressed;
-			}
-
-			break;
-		    }
-		case XineCommands::SetCurrentAudioChannel: {
-			qint8 currentAudioChannel_ = reader->readChar();
-
-			if (reader->isValid()) {
-				currentAudioChannel = currentAudioChannel_;
-				dirtyFlags |= SetCurrentAudioChannel;
-			}
-
-			break;
-		    }
-		case XineCommands::SetCurrentSubtitle: {
-			qint8 currentSubtitle_ = reader->readChar();
-
-			if (reader->isValid()) {
-				currentSubtitle = currentSubtitle_;
-				dirtyFlags |= SetCurrentSubtitle;
-			}
-
-			break;
-		    }
-		case XineCommands::ToggleMenu:
-			dirtyFlags |= ToggleMenu;
-			break;
-		default:
-			Log("XineObject::readyRead: unknown command") << command;
-			continue;
-		}
-
-		if (!reader->isValid()) {
-			Log("XineObject::readyRead: wrong argument size for command") << command;
-		}
-
-		if (((dirtyFlags & (Quit | NotReady | ProcessEvent)) == 0) && (dirtyFlags != 0)) {
-			QCoreApplication::postEvent(this, new QEvent(ReaderEvent));
-			dirtyFlags |= ProcessEvent;
-		}
-	}
-}
-
-void XineObject::updatePosition()
-{
-	int relativePosition;
-	int currentTime;
-	int totalTime;
-
-	if (xine_get_pos_length(stream, &relativePosition, &currentTime, &totalTime) == 1) \
                {
-		parentProcess->updateCurrentTotalTime(currentTime, totalTime);
-	}
-}
-
-void XineObject::init(quint64 windowId)
-{
-	if (engine != NULL) {
-		Log("XineObject::init: xine engine is already initialised");
-		return;
-	}
-
-	engine = xine_new();
-
-	if (engine == NULL) {
-		parentProcess->initFailed("Cannot create engine.");
-		return;
-	}
-
-	xine_config_load(engine, QFile::encodeName(KStandardDirs::locateLocal("data",
-		"kaffeine/xine-config")).constData());
-	xine_init(engine);
-
-	QVector<const char *> audioDrivers;
-	audioDrivers.append("auto");
-
-	for (const char *const *it = xine_list_audio_output_plugins(engine); *it != NULL; \
                ++it) {
-		audioDrivers.append(*it);
-	}
-
-	audioDrivers.append(NULL);
-	const char *audioDriver = audioDrivers.at(
-		xine_config_register_enum(engine, "audio.driver", 0,
-		const_cast<char **>(audioDrivers.constData()), "audio driver", NULL, 10,
-		&audio_driver_cb, this));
-	audioDrivers.clear();
-
-	QVector<const char *> videoDrivers;
-	videoDrivers.append("auto");
-
-	for (const char *const *it = xine_list_video_output_plugins(engine); *it != NULL; \
                ++it) {
-		videoDrivers.append(*it);
-	}
-
-	videoDrivers.append(NULL);
-	const char *videoDriver = videoDrivers.at(
-		xine_config_register_enum(engine, "video.driver", 0,
-		const_cast<char **>(videoDrivers.constData()), "video driver", NULL, 10,
-		&video_driver_cb, this));
-	videoDrivers.clear();
-
-	QLatin1String pixelAspectRatioString(xine_config_register_string(engine,
-		"video.pixel_aspect_ratio", "", "override pixel aspect ratio", NULL, 10,
-		&pixel_aspect_ratio_cb, this));
-
-	bool ok;
-	pixelAspectRatio = QString(pixelAspectRatioString).toDouble(&ok);
-
-	if (!ok || (pixelAspectRatio < 0.1) || (pixelAspectRatio > 10)) {
-		if (qstrlen(pixelAspectRatioString.latin1()) != 0) {
-			Log("XineObject::init: invalid pixel aspect ratio") <<
-				pixelAspectRatioString;
-		}
-
-		pixelAspectRatio = static_cast<double>(QX11Info::appDpiY()) / QX11Info::appDpiX();
-
-		if ((pixelAspectRatio >= 0.96) || (pixelAspectRatio <= 1.04)) {
-			pixelAspectRatio = 1;
-		}
-	}
-
-	audioOutput = xine_open_audio_driver(engine, audioDriver, NULL);
-
-	if (audioOutput == NULL) {
-		Log("XineObject::init: cannot create audio output") << QLatin1String(audioDriver);
-		audioOutput = xine_open_audio_driver(engine, NULL, NULL);
-
-		if (audioOutput == NULL) {
-			parentProcess->initFailed("Cannot create audio output.");
-			return;
-		}
-	}
-
-	x11_visual_t videoOutputData;
-	memset(&videoOutputData, 0, sizeof(videoOutputData));
-	videoOutputData.display = QX11Info::display();
-	videoOutputData.screen = QX11Info::appScreen();
-	videoOutputData.d = windowId;
-	videoOutputData.user_data = this;
-	videoOutputData.dest_size_cb = &dest_size_cb;
-	videoOutputData.frame_output_cb = &frame_output_cb;
-
-	videoOutput = xine_open_video_driver(engine, videoDriver, XINE_VISUAL_TYPE_X11,
-		&videoOutputData);
-
-	if (videoOutput == NULL) {
-		Log("XineObject::init: cannot create video output") << QLatin1String(videoDriver);
-		videoOutput = xine_open_video_driver(engine, NULL, XINE_VISUAL_TYPE_X11,
-			&videoOutputData);
-
-		if (videoOutput == NULL) {
-			parentProcess->initFailed("Cannot create video output.");
-			return;
-		}
-	}
-
-	stream = xine_stream_new(engine, audioOutput, videoOutput);
-
-	if (stream == NULL) {
-		parentProcess->initFailed("Cannot create stream.");
-		return;
-	}
-
-	eventQueue = xine_event_new_queue(stream);
-
-	if (eventQueue == NULL) {
-		parentProcess->initFailed("Cannot create event queue.");
-		return;
-	}
-
-	xine_event_create_listener_thread(eventQueue, &event_listener_cb, this);
-	dirtyFlags &= ~NotReady;
-
-	visualization = NULL; // xine_post_init(engine, "goom", 0, &audioOutput, \
                &videoOutput);
-
-	if (visualization == NULL) {
-		// kWarning() << "cannot create audio visualization plugin";
-	} else {
-		xine_post_in_t *input = xine_post_input(visualization, "audio in");
-
-		if (input == NULL) {
-			Log("XineObject::init: cannot connect audio visualization plugin");
-		} else {
-			xine_post_wire(xine_get_audio_source(stream), input);
-		}
-	}
-
-	deinterlacer = xine_post_init(engine, "tvtime", 1, 0, &videoOutput);
-
-	if (deinterlacer == NULL) {
-		Log("XineObject::init: cannot create deinterlace plugin");
-		return;
-	}
-
-	xine_post_in_t *input = xine_post_input(deinterlacer, "parameters");
-
-	if (input == NULL) {
-		Log("XineObject::init: cannot configure deinterlace plugin");
-		return;
-	}
-
-	xine_post_api_t *deinterlacerApi = static_cast<xine_post_api_t *>(input->data);
-
-	if (deinterlacerApi == NULL) {
-		Log("XineObject::init: cannot configure deinterlace plugin");
-		return;
-	}
-
-	xine_post_api_descr_t *deinterlacerParameters = deinterlacerApi->get_param_descr();
-
-	if (deinterlacerParameters == NULL) {
-		Log("XineObject::init: cannot configure deinterlace plugin");
-		return;
-	}
-
-	for (int i = 0; deinterlacerParameters->parameter[i].type != POST_PARAM_TYPE_LAST; \
                ++i) {
-		xine_post_api_parameter_t &parameter = deinterlacerParameters->parameter[i];
-
-		if ((parameter.type == POST_PARAM_TYPE_INT) &&
-		    (strcmp(parameter.name, "method") == 0)) {
-			QByteArray parameterData;
-			parameterData.resize(deinterlacerParameters->struct_size);
-			char *data = parameterData.data();
-			deinterlacerApi->get_parameters(deinterlacer, data);
-			int *method = reinterpret_cast<int *>(data + parameter.offset);
-
-			for (char **value = parameter.enum_values; *value != NULL; ++value) {
-				if (strcmp(*value, "Greedy2Frame") == 0) {
-					*method = value - parameter.enum_values;
-					break;
-				}
-			}
-
-			deinterlacerApi->set_parameters(deinterlacer, data);
-			break;
-		}
-	}
-
-	// FIXME gapless playback?
-}
-
-void XineObject::customEvent(QEvent *event)
-{
-	if (event->type() == XineEvent) {
-		QMutexLocker locker(&mutex);
-
-		if ((dirtyFlags & (Quit | OpenStream)) != 0) {
-			errorMessage.clear();
-			xineDirtyFlags = 0;
-		}
-
-		while (xineDirtyFlags != 0) {
-			int lowestDirtyFlag = xineDirtyFlags & (~(xineDirtyFlags - 1));
-			xineDirtyFlags &= ~lowestDirtyFlag;
-
-			switch (lowestDirtyFlag) {
-			case PlaybackFailed:
-				parentProcess->playbackFailed(errorMessage);
-				errorMessage.clear();
-				xineDirtyFlags = CloseStream;
-				break;
-			case PlaybackFinished:
-				parentProcess->playbackFinished();
-				xineDirtyFlags = CloseStream;
-				break;
-			case CloseStream:
-				positionTimer.stop();
-				xine_close(stream);
-				break;
-			case UpdateStreamInfo: {
-				QString metadata;
-				metadata.append(QChar(XineMetadataTitle));
-				metadata.append(QString::fromUtf8(xine_get_meta_info(stream,
-					XINE_META_INFO_TITLE)));
-				metadata.append(QChar('\0'));
-				metadata.append(QChar(XineMetadataArtist));
-				metadata.append(QString::fromUtf8(xine_get_meta_info(stream,
-					XINE_META_INFO_ARTIST)));
-				metadata.append(QChar('\0'));
-				metadata.append(QChar(XineMetadataAlbum));
-				metadata.append(QString::fromUtf8(xine_get_meta_info(stream,
-					XINE_META_INFO_ALBUM)));
-				metadata.append(QChar('\0'));
-				metadata.append(QChar(XineMetadataTrackNumber));
-				metadata.append(QString::fromUtf8(xine_get_meta_info(stream,
-					XINE_META_INFO_TRACK_NUMBER)));
-				metadata.append(QChar('\0'));
-				parentProcess->updateMetadata(metadata);
-
-				bool seekable = (xine_get_stream_info(stream,
-					XINE_STREAM_INFO_SEEKABLE) != 0);
-				parentProcess->updateSeekable(seekable);
-
-				QByteArray audioChannels;
-				int audioChannelCount = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
-				int currentAudioChannel = xine_get_param(stream,
-					XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
-
-				for (int i = 0; i < audioChannelCount; ++i) {
-					char langBuffer[XINE_LANG_MAX];
-
-					if (xine_get_audio_lang(stream, i, langBuffer) == 1) {
-						audioChannels.append(langBuffer);
-					}
-
-					audioChannels.append('\0');
-				}
-
-				parentProcess->updateAudioChannels(audioChannels,
-					currentAudioChannel);
-
-				QByteArray subtitles;
-				int subtitleCount = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_MAX_SPU_CHANNEL);
-				int currentSubtitle = xine_get_param(stream,
-					XINE_PARAM_SPU_CHANNEL);
-
-				for (int i = 0; i < subtitleCount; ++i) {
-					char langBuffer[XINE_LANG_MAX];
-
-					if (xine_get_spu_lang(stream, i, langBuffer) == 1) {
-						subtitles.append(langBuffer);
-					}
-
-					subtitles.append('\0');
-				}
-
-				parentProcess->updateSubtitles(subtitles, currentSubtitle);
-
-				int titleCount = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_DVD_TITLE_COUNT);
-				int currentTitle = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_DVD_TITLE_NUMBER);
-
-				if ((titleCount <= 0) && (overrideTitleCount > 0)) {
-					titleCount = overrideTitleCount;
-				}
-
-				if ((currentTitle <= 0) && (overrideCurrentTitle > 0)) {
-					currentTitle = overrideCurrentTitle;
-				}
-
-				parentProcess->updateTitles(titleCount, currentTitle);
-
-				int chapterCount = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_DVD_CHAPTER_COUNT);
-				int currentChapter = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
-				parentProcess->updateChapters(chapterCount, currentChapter);
-
-				int angleCount = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_DVD_ANGLE_COUNT);
-				int currentAngle = xine_get_stream_info(stream,
-					XINE_STREAM_INFO_DVD_ANGLE_NUMBER);
-				parentProcess->updateAngles(angleCount, currentAngle);
-				break;
-			    }
-			case UpdateMouseTracking:
-				parentProcess->updateMouseTracking(mouseTrackingEnabled);
-				break;
-			case UpdateMouseCursor:
-				parentProcess->updateMouseCursor(pointingMouseCursor);
-				break;
-			case UpdateVideoSize:
-				parentProcess->updateVideoSize(videoSize);
-				break;
-			case ProcessXineEvent:
-				break;
-			default:
-				Log("XineObject::customEvent: unknown flag") << lowestDirtyFlag;
-				break;
-			}
-		}
-
-		return;
-	}
-
-	while (dirtyFlags != 0) {
-		QCoreApplication::processEvents();
-		int lowestDirtyFlag = dirtyFlags & (~(dirtyFlags - 1));
-		dirtyFlags &= ~lowestDirtyFlag;
-
-		switch (lowestDirtyFlag) {
-		case Quit:
-			return;
-		case SetMuted:
-			xine_set_param(stream, XINE_PARAM_AUDIO_AMP_MUTE, muted);
-			break;
-		case SetVolume:
-			xine_set_param(stream, XINE_PARAM_AUDIO_AMP_LEVEL, volume);
-			break;
-		case SetAspectRatio: {
-			int xineAspectRatio;
-
-			switch (aspectRatio) {
-			case XineAspectRatioAuto:
-				xineAspectRatio = XINE_VO_ASPECT_AUTO;
-				break;
-			case XineAspectRatio4_3:
-				xineAspectRatio = XINE_VO_ASPECT_4_3;
-				break;
-			case XineAspectRatio16_9:
-				xineAspectRatio = XINE_VO_ASPECT_ANAMORPHIC;
-				break;
-			case XineAspectRatioWidget:
-				// this is solved via xine frame callbacks
-				xineAspectRatio = XINE_VO_ASPECT_SQUARE;
-				break;
-			default:
-				Log("XineObject::customEvent: unknown aspect ratio") <<
-					aspectRatio;
-				xineAspectRatio = XINE_VO_ASPECT_AUTO;
-				break;
-			}
-
-			xine_set_param(stream, XINE_PARAM_VO_ASPECT_RATIO, xineAspectRatio);
-			break;
-		    }
-		case SetDeinterlacing:
-			if (deinterlacing && (deinterlacer != NULL)) {
-				xine_post_in_t *input = xine_post_input(deinterlacer, "video");
-
-				if (input != NULL) {
-					xine_post_wire(xine_get_video_source(stream), input);
-				}
-			} else {
-				xine_post_wire_video_port(xine_get_video_source(stream),
-					videoOutput);
-			}
-
-			break;
-		case OpenStream:
-			parentProcess->sync(sequenceNumber);
-			overrideTitleCount = 0;
-			overrideCurrentTitle = 0;
-
-			if (encodedUrl.startsWith("cdda:")) {
-				xine_get_autoplay_input_plugin_ids(engine);
-				xine_get_autoplay_mrls(engine, "CD", &overrideTitleCount);
-				overrideCurrentTitle =
-					encodedUrl.mid(encodedUrl.lastIndexOf('/') + 1).toInt();
-
-				if (overrideCurrentTitle < 1) {
-					overrideCurrentTitle = 1;
-				}
-			}
-
-			if (!encodedUrl.isEmpty()) {
-				if (xine_open(stream, encodedUrl.constData()) == 1) {
-					mutex.lock();
-					errorMessage.clear();
-					xineDirtyFlags &= ~(PlaybackFailed | PlaybackFinished);
-					mutex.unlock();
-					dirtyFlags |= PlayStream;
-				} else {
-					int errorCode = xine_get_error(stream);
-					// xine_close is called when dealing with PlaybackFailed
-					mutex.lock();
-
-					if (errorMessage.isEmpty()) {
-						errorMessage = xineErrorString(errorCode);
-					}
-
-					xineDirtyFlags |= PlaybackFailed;
-					postXineEvent();
-					mutex.unlock();
-				}
-
-				encodedUrl.clear();
-			} else {
-				// xine_close is called when dealing with PlaybackFinished
-				mutex.lock();
-				xineDirtyFlags |= PlaybackFinished;
-				postXineEvent();
-				mutex.unlock();
-			}
-
-			break;
-		case PlayStream:
-			if (xine_play(stream, 0, 0) == 1) {
-				mutex.lock();
-				xineDirtyFlags |= UpdateStreamInfo;
-				postXineEvent();
-				mutex.unlock();
-				positionTimer.start();
-				updatePosition();
-			} else {
-				int errorCode = xine_get_error(stream);
-				// xine_close is called when dealing with PlaybackFailed
-				mutex.lock();
-
-				if (errorMessage.isEmpty()) {
-					errorMessage = xineErrorString(errorCode);
-				}
-
-				xineDirtyFlags |= PlaybackFailed;
-				postXineEvent();
-				mutex.unlock();
-			}
-
-			break;
-		case SetPaused:
-			if (paused) {
-				xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
-			} else {
-				xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
-			}
-
-			break;
-		case Seek:
-			xine_play(stream, 0, seekTime);
-			break;
-		case Repaint: {
-			XEvent event;
-			memset(&event, 0, sizeof(event));
-			event.xexpose.type = Expose;
-			event.xexpose.width = (widgetSize >> 16);
-			event.xexpose.height = (widgetSize & 0xffff);
-			xine_port_send_gui_data(videoOutput, XINE_GUI_SEND_EXPOSE_EVENT, &event);
-			break;
-		    }
-		case MouseMoved: {
-			x11_rectangle_t rectangle;
-			memset(&rectangle, 0, sizeof(rectangle));
-			rectangle.x = (mouseMovePosition >> 16);
-			rectangle.y = (mouseMovePosition & 0xffff);
-			xine_port_send_gui_data(videoOutput, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO,
-				&rectangle);
-			xine_input_data_t input;
-			memset(&input, 0, sizeof(input));
-			input.event.type = XINE_EVENT_INPUT_MOUSE_MOVE;
-			input.event.data = &input;
-			input.event.data_length = sizeof(input);
-			input.x = rectangle.x;
-			input.y = rectangle.y;
-			xine_event_send(stream, &input.event);
-			break;
-		    }
-		case MousePressed: {
-			x11_rectangle_t rectangle;
-			memset(&rectangle, 0, sizeof(rectangle));
-			rectangle.x = (mousePressPosition >> 16);
-			rectangle.y = (mousePressPosition & 0xffff);
-			xine_port_send_gui_data(videoOutput, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO,
-				&rectangle);
-			xine_input_data_t input;
-			memset(&input, 0, sizeof(input));
-			input.event.type = XINE_EVENT_INPUT_MOUSE_BUTTON;
-			input.event.data = &input;
-			input.event.data_length = sizeof(input);
-			input.button = 1;
-			input.x = rectangle.x;
-			input.y = rectangle.y;
-			xine_event_send(stream, &input.event);
-			break;
-		    }
-		case SetCurrentAudioChannel:
-			xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
-				currentAudioChannel);
-			break;
-		case SetCurrentSubtitle:
-			xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, currentSubtitle);
-			break;
-		case ToggleMenu: {
-			xine_event_t event;
-			memset(&event, 0, sizeof(event));
-			event.type = XINE_EVENT_INPUT_MENU1;
-			xine_event_send(stream, &event);
-			break;
-		    }
-		case ProcessEvent:
-			break;
-		default:
-			Log("XineObject::customEvent: unknown flag") << lowestDirtyFlag;
-			break;
-		}
-	}
-}
-
-QString XineObject::xineErrorString(int errorCode) const
-{
-	switch (errorCode) {
-	case XINE_ERROR_NO_INPUT_PLUGIN:
-		return QString("Cannot find input plugin for MRL \"") + encodedUrl + "\".";
-	case XINE_ERROR_INPUT_FAILED:
-		return QString("Cannot open input plugin for MRL \"") + encodedUrl + "\".";
-	case XINE_ERROR_NO_DEMUX_PLUGIN:
-		return QString("Cannot find demux plugin for MRL \"") + encodedUrl + "\".";
-	case XINE_ERROR_DEMUX_FAILED:
-		return QString("Cannot open demux plugin for MRL \"") + encodedUrl + "\".";
-	case XINE_ERROR_MALFORMED_MRL:
-		return QString("Cannot parse MRL \"") + encodedUrl + "\".";
-	case XINE_ERROR_NONE:
-	default:
-		return QString("Cannot open MRL \"") + encodedUrl + "\".";
-	}
-}
-
-void XineObject::postXineEvent()
-{
-	if ((xineDirtyFlags & ProcessXineEvent) == 0) {
-		QCoreApplication::postEvent(this, new QEvent(XineEvent));
-		xineDirtyFlags |= ProcessXineEvent;
-	}
-}
-
-void XineObject::audio_driver_cb(void *user_data, xine_cfg_entry_t *entry)
-{
-	Q_UNUSED(user_data)
-	Q_UNUSED(entry)
-}
-
-void XineObject::video_driver_cb(void *user_data, xine_cfg_entry_t *entry)
-{
-	Q_UNUSED(user_data)
-	Q_UNUSED(entry)
-}
-
-void XineObject::pixel_aspect_ratio_cb(void *user_data, xine_cfg_entry_t *entry)
-{
-	Q_UNUSED(user_data)
-	Q_UNUSED(entry)
-}
-
-void XineObject::dest_size_cb(void *user_data, int video_width, int video_height,
-	double video_pixel_aspect, int *dest_width, int *dest_height, double \
                *dest_pixel_aspect)
-{
-	XineObject *instance = static_cast<XineObject *>(user_data);
-	int widgetSize = instance->widgetSize;
-	*dest_width = (widgetSize >> 16);
-	*dest_height = (widgetSize & 0xffff);
-
-	if (instance->aspectRatio != XineAspectRatioWidget) {
-		*dest_pixel_aspect = instance->pixelAspectRatio;
-	} else {
-		*dest_pixel_aspect = video_pixel_aspect * video_width * (widgetSize & 0xffff) /
-			(video_height * (widgetSize >> 16));
-	}
-
-	unsigned int videoSize = ((video_width << 16) | video_height);
-
-	if (instance->videoSize != videoSize) {
-		QMutexLocker locker(&instance->mutex);
-		instance->videoSize = videoSize;
-		instance->xineDirtyFlags |= UpdateVideoSize;
-		instance->postXineEvent();
-	}
-}
-
-void XineObject::frame_output_cb(void *user_data, int video_width, int video_height,
-	double video_pixel_aspect, int *dest_x, int *dest_y, int *dest_width, int \
                *dest_height,
-	double *dest_pixel_aspect, int *win_x, int *win_y)
-{
-	XineObject *instance = static_cast<XineObject *>(user_data);
-	*dest_x = 0;
-	*dest_y = 0;
-	int widgetSize = instance->widgetSize;
-	*dest_width = (widgetSize >> 16);
-	*dest_height = (widgetSize & 0xffff);
-	*win_x = 0;
-	*win_y = 0;
-
-	if (instance->aspectRatio != XineAspectRatioWidget) {
-		*dest_pixel_aspect = instance->pixelAspectRatio;
-	} else {
-		*dest_pixel_aspect = video_pixel_aspect * video_width * (widgetSize & 0xffff) /
-			(video_height * (widgetSize >> 16));
-	}
-
-	unsigned int videoSize = ((video_width << 16) | video_height);
-
-	if (instance->videoSize != videoSize) {
-		QMutexLocker locker(&instance->mutex);
-		instance->videoSize = videoSize;
-		instance->xineDirtyFlags |= UpdateVideoSize;
-		instance->postXineEvent();
-	}
-}
-
-void XineObject::event_listener_cb(void *user_data, const xine_event_t *event)
-{
-	XineObject *instance = static_cast<XineObject *>(user_data);
-
-	switch (event->type) {
-	case XINE_EVENT_UI_PLAYBACK_FINISHED: {
-		QMutexLocker locker(&instance->mutex);
-		instance->xineDirtyFlags |= PlaybackFinished;
-		instance->postXineEvent();
-		break;
-	    }
-	case XINE_EVENT_UI_CHANNELS_CHANGED: {
-		QMutexLocker locker(&instance->mutex);
-		instance->xineDirtyFlags |= UpdateStreamInfo;
-		instance->postXineEvent();
-		break;
-	    }
-	case XINE_EVENT_UI_MESSAGE: {
-		QMutexLocker locker(&instance->mutex);
-		const xine_ui_message_data_t *messageData =
-			static_cast<const xine_ui_message_data_t *>(event->data);
-
-		if (messageData != NULL) {
-			const char *data = messageData->messages;
-			int size = 0;
-
-			while (data[size + 1] != '\0') {
-				++size;
-				size += qstrlen(data + size);
-			}
-
-			instance->errorMessage = QString::fromLocal8Bit(data, size);
-			instance->errorMessage.replace('\0', '\n');
-		} else {
-			instance->errorMessage.clear();
-		}
-
-		instance->xineDirtyFlags |= PlaybackFailed;
-		instance->postXineEvent();
-		break;
-	    }
-	case XINE_EVENT_UI_NUM_BUTTONS: {
-		QMutexLocker locker(&instance->mutex);
-		const xine_ui_data_t *uiData = static_cast<const xine_ui_data_t *>(event->data);
-
-		if (uiData != NULL) {
-			instance->mouseTrackingEnabled = (uiData->num_buttons != 0);
-		} else {
-			instance->mouseTrackingEnabled = false;
-		}
-
-		instance->xineDirtyFlags |= UpdateMouseTracking;
-		instance->postXineEvent();
-		break;
-	    }
-	case XINE_EVENT_SPU_BUTTON: {
-		QMutexLocker locker(&instance->mutex);
-		const xine_spu_button_t *spu_event =
-			static_cast<const xine_spu_button_t *>(event->data);
-
-		if (spu_event != NULL) {
-			instance->pointingMouseCursor = (spu_event->direction == 1);
-		} else {
-			instance->pointingMouseCursor = false;
-		}
-
-		instance->xineDirtyFlags |= UpdateMouseCursor;
-		instance->postXineEvent();
-		break;
-	    }
-	}
-}
-
-int main(int argc, char *argv[])
-{
-	XInitThreads();
-
-	bool ok = false;
-
-	if ((argc == 2) && (strcmp(argv[1], "fU4eT3iN") == 0)) {
-		ok = true;
-		argc = 1;
-	}
-
-	KAboutData aboutData("kaffeine-xbu", "kaffeine", ki18n("Kaffeine"),
-		QByteArray("1.3-svn ").append(XineObject::version()),
-		ki18nc("program description", "Internal utility for Kaffeine."),
-		KAboutData::License_GPL_V2, ki18n("(C) 2007-2011 The Kaffeine Authors"),
-		KLocalizedString(), "http://kaffeine.kde.org");
-	aboutData.addAuthor(ki18n("Christoph Pfister"), ki18n("Maintainer"),
-		"christophpfister@gmail.com");
-	KCmdLineArgs::init(argc, argv, &aboutData);
-
-	KApplication application;
-
-	if (!ok) {
-		return 0;
-	}
-
-	XineObject xineObject;
-	return application.exec();
-}
diff --git a/src/backend-xine/xineapplication.h b/src/backend-xine/xineapplication.h
deleted file mode 100644
index 3fcccd4..0000000
--- a/src/backend-xine/xineapplication.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * xineapplication.h
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#ifndef XINEAPPLICATION_H
-#define XINEAPPLICATION_H
-
-#include <QEvent>
-#include <QMutex>
-#include <QTimer>
-#include <xine.h>
-
-class XineParent;
-class XinePipeReader;
-
-class XineObject : public QObject
-{
-	Q_OBJECT
-public:
-	XineObject();
-	~XineObject();
-
-	static const char *version();
-
-private slots:
-	void readyRead();
-	void updatePosition();
-
-private:
-	enum DirtyFlag {
-		Quit			= (1 <<  0),
-		NotReady		= (1 <<  1),
-		SetMuted		= (1 <<  2),
-		SetVolume		= (1 <<  3),
-		SetAspectRatio		= (1 <<  4),
-		SetDeinterlacing	= (1 <<  5),
-		OpenStream		= (1 <<  6),
-		PlayStream		= (1 <<  7),
-		SetPaused		= (1 <<  8),
-		Seek			= (1 <<  9),
-		Repaint			= (1 << 10),
-		MouseMoved		= (1 << 11),
-		MousePressed		= (1 << 12),
-		SetCurrentAudioChannel	= (1 << 13),
-		SetCurrentSubtitle	= (1 << 14),
-		ToggleMenu		= (1 << 15),
-		ProcessEvent		= (1 << 30)
-	};
-
-	Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
-
-	enum XineDirtyFlag {
-		PlaybackFailed		= (1 <<  0),
-		PlaybackFinished	= (1 <<  1),
-		CloseStream		= (1 <<  2),
-		UpdateStreamInfo	= (1 <<  3),
-		UpdateMouseTracking	= (1 <<  4),
-		UpdateMouseCursor	= (1 <<  5),
-		UpdateVideoSize		= (1 <<  6),
-		ProcessXineEvent	= (1 << 30)
-	};
-
-	Q_DECLARE_FLAGS(XineDirtyFlags, XineDirtyFlag)
-
-	static const QEvent::Type ReaderEvent = static_cast<QEvent::Type>(QEvent::User + \
                1);
-	static const QEvent::Type XineEvent = static_cast<QEvent::Type>(QEvent::User + 2);
-
-	void init(quint64 windowId);
-	void customEvent(QEvent *event);
-	QString xineErrorString(int errorCode) const;
-
-	void postXineEvent();
-	static void audio_driver_cb(void *user_data, xine_cfg_entry_t *entry);
-	static void video_driver_cb(void *user_data, xine_cfg_entry_t *entry);
-	static void pixel_aspect_ratio_cb(void *user_data, xine_cfg_entry_t *entry);
-	static void dest_size_cb(void *user_data, int video_width, int video_height,
-		double video_pixel_aspect, int *dest_width, int *dest_height,
-		double *dest_pixel_aspect);
-	static void frame_output_cb(void *user_data, int video_width, int video_height,
-		double video_pixel_aspect, int *dest_x, int *dest_y, int *dest_width,
-		int *dest_height, double *dest_pixel_aspect, int *win_x, int *win_y);
-	static void event_listener_cb(void *user_data, const xine_event_t *event);
-
-	XinePipeReader *reader;
-	XineParent *parentProcess;
-
-	xine_t *engine;
-	xine_audio_port_t *audioOutput;
-	xine_video_port_t *videoOutput;
-	xine_stream_t *stream;
-	xine_event_queue_t *eventQueue;
-	xine_post_t *visualization;
-	xine_post_t *deinterlacer;
-	double pixelAspectRatio;
-	unsigned int widgetSize;
-	QTimer positionTimer;
-	int overrideTitleCount;
-	int overrideCurrentTitle;
-
-	DirtyFlags dirtyFlags;
-	bool muted;
-	bool deinterlacing;
-	bool paused;
-	int aspectRatio;
-	int currentAudioChannel;
-	int currentSubtitle;
-	int seekTime;
-	int volume;
-	unsigned int mouseMovePosition;
-	unsigned int mousePressPosition;
-	unsigned int sequenceNumber;
-	QByteArray encodedUrl;
-
-	QMutex mutex;
-	XineDirtyFlags xineDirtyFlags;
-	bool mouseTrackingEnabled;
-	bool pointingMouseCursor;
-	unsigned int videoSize;
-	QString errorMessage;
-};
-
-#endif /* XINEAPPLICATION_H */
diff --git a/src/backend-xine/xinecommands.cpp b/src/backend-xine/xinecommands.cpp
deleted file mode 100644
index 737ebb7..0000000
--- a/src/backend-xine/xinecommands.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * xinecommands.cpp
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#include "xinecommands.h"
-
-#include <errno.h>
-#include <unistd.h>
-#include "../log.h"
-
-XinePipeReader::XinePipeReader(int fd_, QObject *parent) : fd(fd_),
-	notifier(fd, QSocketNotifier::Read)
-{
-	QObject::connect(&notifier, SIGNAL(activated(int)), parent, SLOT(readyRead()));
-
-	buffer.resize(4080);
-	bufferPosition = 0;
-	bufferSize = 0;
-	currentData = NULL;
-	currentSize = -1;
-}
-
-XinePipeReader::~XinePipeReader()
-{
-}
-
-void XinePipeReader::readyRead()
-{
-	while (true) {
-		int bytesRead = read(fd, buffer.data() + bufferSize, buffer.size() - bufferSize);
-
-		if ((bytesRead < 0) && (errno == EINTR)) {
-			continue;
-		}
-
-		if (bytesRead > 0) {
-			bufferSize += bytesRead;
-
-			if (bufferSize == buffer.size()) {
-				buffer.resize(buffer.size() + 4096);
-				continue;
-			}
-		}
-
-		break;
-	}
-
-	currentSize = -1;
-}
-
-int XinePipeReader::nextCommand()
-{
-	qint32 size = 5;
-
-	if ((bufferSize - bufferPosition) >= 4) {
-		memcpy(&size, buffer.constData() + bufferPosition, 4);
-
-		if (size < 5) {
-			Log("XinePipeReader::nextCommand: size too small");
-			size = 5;
-		}
-	}
-
-	if ((bufferSize - bufferPosition) < size) {
-		if (bufferPosition == bufferSize) {
-			if (buffer.size() != 4080) {
-				buffer.clear();
-				buffer.resize(4080);
-			}
-
-			bufferPosition = 0;
-			bufferSize = 0;
-		} else if (bufferPosition > 0) {
-			memmove(buffer.data(), buffer.constData() + bufferPosition,
-				bufferSize - bufferPosition);
-			bufferSize -= bufferPosition;
-			bufferPosition = 0;
-
-			if (buffer.size() < size) {
-				buffer.resize(4080 + ((size - 4080 + 4095) & (~4095)));
-			} else if ((buffer.size() > 4080) && (size <= 4080)) {
-				buffer.resize(4080);
-			}
-		}
-
-		currentSize = -1;
-		return -1;
-	}
-
-	currentData = buffer.constData() + bufferPosition + 5;
-	currentSize = size - 5;
-	bufferPosition += size;
-	return *(currentData - 1);
-}
-
-bool XinePipeReader::isValid() const
-{
-	return (currentSize == 0);
-}
-
-bool XinePipeReader::readBool()
-{
-	bool value = false;
-
-	if (currentSize >= 1) {
-		value = (*currentData != 0);
-		++currentData;
-		--currentSize;
-	} else {
-		currentSize = -1;
-	}
-
-	return value;
-}
-
-qint8 XinePipeReader::readChar()
-{
-	qint8 value = 0;
-
-	if (currentSize >= static_cast<int>(sizeof(value))) {
-		memcpy(&value, currentData, sizeof(value));
-		currentData += sizeof(value);
-		currentSize -= sizeof(value);
-	} else {
-		currentSize = -1;
-	}
-
-	return value;
-}
-
-qint16 XinePipeReader::readShort()
-{
-	qint16 value = 0;
-
-	if (currentSize >= static_cast<int>(sizeof(value))) {
-		memcpy(&value, currentData, sizeof(value));
-		currentData += sizeof(value);
-		currentSize -= sizeof(value);
-	} else {
-		currentSize = -1;
-	}
-
-	return value;
-}
-
-qint32 XinePipeReader::readInt()
-{
-	qint32 value = 0;
-
-	if (currentSize >= static_cast<int>(sizeof(value))) {
-		memcpy(&value, currentData, sizeof(value));
-		currentData += sizeof(value);
-		currentSize -= sizeof(value);
-	} else {
-		currentSize = -1;
-	}
-
-	return value;
-}
-
-qint64 XinePipeReader::readLongLong()
-{
-	qint64 value = 0;
-
-	if (currentSize >= static_cast<int>(sizeof(value))) {
-		memcpy(&value, currentData, sizeof(value));
-		currentData += sizeof(value);
-		currentSize -= sizeof(value);
-	} else {
-		currentSize = -1;
-	}
-
-	return value;
-}
-
-QByteArray XinePipeReader::readByteArray()
-{
-	QByteArray byteArray;
-
-	if (currentSize >= 0) {
-		byteArray.resize(currentSize);
-		memcpy(byteArray.data(), currentData, currentSize);
-		currentSize = 0;
-	}
-
-	return byteArray;
-}
-
-QString XinePipeReader::readString()
-{
-	QString string;
-
-	if ((currentSize >= 0) && ((currentSize & 0x01) == 0)) {
-		string.resize(currentSize / 2);
-		memcpy(reinterpret_cast<char *>(string.data()), currentData, currentSize);
-		currentSize = 0;
-	} else {
-		currentSize = -1;
-	}
-
-	return string;
-}
-
-void XinePipeWriterBase::write(qint8 command, const char *firstArg, unsigned int \
                firstArgSize,
-	const char *secondArg, unsigned int secondArgSize)
-{
-	Q_UNUSED(command)
-	Q_UNUSED(firstArg)
-	Q_UNUSED(firstArgSize)
-	Q_UNUSED(secondArg)
-	Q_UNUSED(secondArgSize)
-}
-
-XinePipeWriter::XinePipeWriter(int fd_, QObject *parent) : QObject(parent), fd(fd_),
-	notifier(fd, QSocketNotifier::Write)
-{
-	notifier.setEnabled(false);
-	connect(&notifier, SIGNAL(activated(int)), this, SLOT(readyWrite()));
-
-	buffer.resize(4080);
-	bufferPosition = 0;
-}
-
-XinePipeWriter::~XinePipeWriter()
-{
-}
-
-void XinePipeWriter::readyWrite()
-{
-	if (flush()) {
-		notifier.setEnabled(false);
-	}
-}
-
-void XinePipeWriter::write(qint8 command, const char *firstArg, unsigned int \
                firstArgSize,
-	const char *secondArg, unsigned int secondArgSize)
-{
-	if ((firstArgSize >= 0x100000) || (secondArgSize >= 0x100000)) {
-		Log("XinePipeWriter::write: monstrous big write") << command;
-		firstArgSize = 0;
-		secondArgSize = 0;
-	}
-
-	qint32 size = 5 + firstArgSize + secondArgSize;
-
-	if (size > (buffer.size() - bufferPosition)) {
-		buffer.resize(4080 + ((bufferPosition + size - 4080 + 4095) & (~4095)));
-	}
-
-	char *data = buffer.data() + bufferPosition;
-	memcpy(data, &size, 4);
-	data[4] = command;
-	memcpy(data + 5, firstArg, firstArgSize);
-	memcpy(data + 5 + firstArgSize, secondArg, secondArgSize);
-	bufferPosition += size;
-
-	if (!flush()) {
-		notifier.setEnabled(true);
-	}
-}
-
-bool XinePipeWriter::flush()
-{
-	int bytesWritten;
-
-	do {
-		bytesWritten = ::write(fd, buffer.constData(), bufferPosition);
-	} while ((bytesWritten < 0) && (errno == EINTR));
-
-	if (bytesWritten > 0) {
-		if (bytesWritten == bufferPosition) {
-			if (buffer.size() != 4080) {
-				buffer.clear();
-				buffer.resize(4080);
-			}
-
-			bufferPosition = 0;
-			return true;
-		}
-
-		memmove(buffer.data(), buffer.constData() + bytesWritten,
-			bufferPosition - bytesWritten);
-		bufferPosition -= bytesWritten;
-	}
-
-	return false;
-}
diff --git a/src/backend-xine/xinecommands.h b/src/backend-xine/xinecommands.h
deleted file mode 100644
index 25759cf..0000000
--- a/src/backend-xine/xinecommands.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * xinecommands.h
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#ifndef XINECOMMANDS_H
-#define XINECOMMANDS_H
-
-#include <QSocketNotifier>
-
-namespace XineCommands
-{
-	enum CommandToChild {
-		Quit			=  0,
-		Init			=  1,
-		Resize			=  2,
-		SetMuted		=  3,
-		SetVolume		=  4,
-		SetAspectRatio		=  5,
-		SetDeinterlacing	=  6,
-		PlayUrl			=  7,
-		SetPaused		=  8,
-		Seek			=  9,
-		Repaint			= 10,
-		MouseMoved		= 11,
-		MousePressed		= 12,
-		SetCurrentAudioChannel	= 13,
-		SetCurrentSubtitle	= 14,
-		ToggleMenu		= 15
-	};
-
-	enum CommandFromChild {
-		InitFailed		=  0,
-		Sync			=  1,
-		PlaybackFailed		=  2,
-		PlaybackFinished	=  3,
-		UpdateCurrentTotalTime	=  4,
-		UpdateMetadata		=  5,
-		UpdateSeekable		=  6,
-		UpdateAudioChannels	=  7,
-		UpdateSubtitles		=  8,
-		UpdateTitles		=  9,
-		UpdateChapters		= 10,
-		UpdateAngles		= 11,
-		UpdateMouseTracking	= 12,
-		UpdateMouseCursor	= 13,
-		UpdateVideoSize		= 14
-	};
-}
-
-enum XineAspectRatio {
-	XineAspectRatioAuto	= 0,
-	XineAspectRatio4_3	= 1,
-	XineAspectRatio16_9	= 2,
-	XineAspectRatioWidget	= 3
-};
-
-enum XineMetadataType {
-	XineMetadataTitle	= 0,
-	XineMetadataArtist	= 1,
-	XineMetadataAlbum	= 2,
-	XineMetadataTrackNumber	= 3
-};
-
-class XinePipeReader
-{
-public:
-	XinePipeReader(int fd_, QObject *parent);
-	~XinePipeReader();
-
-	void readyRead();
-	int nextCommand();
-	bool isValid() const;
-
-	bool readBool();
-	qint8 readChar();
-	qint16 readShort();
-	qint32 readInt();
-	qint64 readLongLong();
-	QByteArray readByteArray();
-	QString readString();
-
-private:
-	int fd;
-	QSocketNotifier notifier;
-	QByteArray buffer;
-	int bufferPosition;
-	int bufferSize;
-	const char *currentData;
-	int currentSize;
-};
-
-class XinePipeWriterBase
-{
-	friend class XineChildMarshaller;
-	friend class XineParentMarshaller;
-public:
-	XinePipeWriterBase() { }
-	virtual ~XinePipeWriterBase() { }
-
-private:
-	virtual void write(qint8 command,
-		const char *firstArg = NULL, unsigned int firstArgSize = 0,
-		const char *secondArg = NULL, unsigned int secondArgSize = 0);
-};
-
-class XinePipeWriter : public QObject, public XinePipeWriterBase
-{
-	Q_OBJECT
-public:
-	XinePipeWriter(int fd_, QObject *parent);
-	~XinePipeWriter();
-
-private slots:
-	void readyWrite();
-
-private:
-	void write(qint8 command, const char *firstArg, unsigned int firstArgSize,
-		const char *secondArg, unsigned int secondArgSize);
-	bool flush();
-
-	int fd;
-	QSocketNotifier notifier;
-	QByteArray buffer;
-	int bufferPosition;
-};
-
-class XineChildMarshaller
-{
-public:
-	XineChildMarshaller() : writer(NULL) { }
-	~XineChildMarshaller() { }
-
-	void quit()
-	{
-		writer->write(XineCommands::Quit);
-	}
-
-	void init(quint64 windowId)
-	{
-		writer->write(XineCommands::Init, reinterpret_cast<const char *>(&windowId),
-			sizeof(windowId));
-	}
-
-	void resize(quint16 width, quint16 height)
-	{
-		writer->write(XineCommands::Resize, reinterpret_cast<const char *>(&width),
-			sizeof(width), reinterpret_cast<const char *>(&height), sizeof(height));
-	}
-
-	void setMuted(bool muted)
-	{
-		writer->write(XineCommands::SetMuted, reinterpret_cast<const char *>(&muted),
-			sizeof(muted));
-	}
-
-	void setVolume(quint8 volume)
-	{
-		writer->write(XineCommands::SetVolume, reinterpret_cast<const char *>(&volume),
-			sizeof(volume));
-	}
-
-	void setAspectRatio(qint8 aspectRatio)
-	{
-		writer->write(XineCommands::SetAspectRatio,
-			reinterpret_cast<const char *>(&aspectRatio), sizeof(aspectRatio));
-	}
-
-	void setDeinterlacing(bool deinterlacing)
-	{
-		writer->write(XineCommands::SetDeinterlacing,
-			reinterpret_cast<const char *>(&deinterlacing), sizeof(deinterlacing));
-	}
-
-	void playUrl(quint32 sequenceNumber, const QByteArray &encodedUrl)
-	{
-		writer->write(XineCommands::PlayUrl,
-			reinterpret_cast<const char *>(&sequenceNumber), sizeof(sequenceNumber),
-			encodedUrl.constData(), encodedUrl.size());
-	}
-
-	void setPaused(bool paused)
-	{
-		writer->write(XineCommands::SetPaused, reinterpret_cast<const char *>(&paused),
-			sizeof(paused));
-	}
-
-	void seek(qint32 time)
-	{
-		writer->write(XineCommands::Seek, reinterpret_cast<const char *>(&time),
-			sizeof(time));
-	}
-
-	void repaint()
-	{
-		writer->write(XineCommands::Repaint);
-	}
-
-	void mouseMoved(quint16 x, quint16 y)
-	{
-		writer->write(XineCommands::MouseMoved, reinterpret_cast<const char *>(&x),
-			sizeof(x), reinterpret_cast<const char *>(&y), sizeof(y));
-	}
-
-	void mousePressed(quint16 x, quint16 y)
-	{
-		writer->write(XineCommands::MousePressed, reinterpret_cast<const char *>(&x),
-			sizeof(x), reinterpret_cast<const char *>(&y), sizeof(y));
-	}
-
-	void setCurrentAudioChannel(qint8 currentAudioChannel)
-	{
-		writer->write(XineCommands::SetCurrentAudioChannel,
-			reinterpret_cast<const char *>(&currentAudioChannel),
-			sizeof(currentAudioChannel));
-	}
-
-	void setCurrentSubtitle(qint8 currentSubtitle)
-	{
-		writer->write(XineCommands::SetCurrentSubtitle,
-			reinterpret_cast<const char *>(&currentSubtitle), sizeof(currentSubtitle));
-	}
-
-	void toggleMenu()
-	{
-		writer->write(XineCommands::ToggleMenu);
-	}
-
-	XinePipeWriterBase *writer;
-};
-
-class XineParentMarshaller
-{
-public:
-	XineParentMarshaller() : writer(NULL) { }
-	~XineParentMarshaller() { }
-
-	void initFailed(const QString &errorMessage)
-	{
-		writer->write(XineCommands::InitFailed,
-			reinterpret_cast<const char *>(errorMessage.constData()),
-			static_cast<unsigned int>(errorMessage.size()) * sizeof(QChar));
-	}
-
-	void sync(quint32 sequenceNumber)
-	{
-		writer->write(XineCommands::Sync, reinterpret_cast<const char *>(&sequenceNumber),
-			sizeof(sequenceNumber));
-	}
-
-	void playbackFailed(const QString &errorMessage)
-	{
-		writer->write(XineCommands::PlaybackFailed,
-			reinterpret_cast<const char *>(errorMessage.constData()),
-			static_cast<unsigned int>(errorMessage.size()) * sizeof(QChar));
-	}
-
-	void playbackFinished()
-	{
-		writer->write(XineCommands::PlaybackFinished);
-	}
-
-	void updateCurrentTotalTime(qint32 currentTime, qint32 totalTime)
-	{
-		writer->write(XineCommands::UpdateCurrentTotalTime,
-			reinterpret_cast<const char *>(&currentTime), sizeof(currentTime),
-			reinterpret_cast<const char *>(&totalTime), sizeof(totalTime));
-	}
-
-	void updateMetadata(const QString &metadata)
-	{
-		writer->write(XineCommands::UpdateMetadata,
-			reinterpret_cast<const char *>(metadata.constData()),
-			static_cast<unsigned int>(metadata.size()) * sizeof(QChar));
-	}
-
-	void updateSeekable(bool seekable)
-	{
-		writer->write(XineCommands::UpdateSeekable,
-			reinterpret_cast<const char *>(&seekable), sizeof(seekable));
-	}
-
-	void updateAudioChannels(const QByteArray &audioChannels, qint8 \
                currentAudioChannel)
-	{
-		writer->write(XineCommands::UpdateAudioChannels,
-			reinterpret_cast<const char *>(&currentAudioChannel),
-			sizeof(currentAudioChannel),
-			audioChannels.constData(), audioChannels.size());
-	}
-
-	void updateSubtitles(const QByteArray &subtitles, qint8 currentSubtitle)
-	{
-		writer->write(XineCommands::UpdateSubtitles,
-			reinterpret_cast<const char *>(&currentSubtitle), sizeof(currentSubtitle),
-			subtitles.constData(), subtitles.size());
-	}
-
-	void updateTitles(qint8 titleCount, qint8 currentTitle)
-	{
-		writer->write(XineCommands::UpdateTitles,
-			reinterpret_cast<const char *>(&titleCount), sizeof(titleCount),
-			reinterpret_cast<const char *>(&currentTitle), sizeof(currentTitle));
-	}
-
-	void updateChapters(qint8 chapterCount, qint8 currentChapter)
-	{
-		writer->write(XineCommands::UpdateChapters,
-			reinterpret_cast<const char *>(&chapterCount), sizeof(chapterCount),
-			reinterpret_cast<const char *>(&currentChapter), sizeof(currentChapter));
-	}
-
-	void updateAngles(qint8 angleCount, qint8 currentAngle)
-	{
-		writer->write(XineCommands::UpdateAngles,
-			reinterpret_cast<const char *>(&angleCount), sizeof(angleCount),
-			reinterpret_cast<const char *>(&currentAngle), sizeof(currentAngle));
-	}
-
-	void updateMouseTracking(bool mouseTrackingEnabled)
-	{
-		writer->write(XineCommands::UpdateMouseTracking,
-			reinterpret_cast<const char *>(&mouseTrackingEnabled),
-			sizeof(mouseTrackingEnabled));
-	}
-
-	void updateMouseCursor(bool pointingMouseCursor)
-	{
-		writer->write(XineCommands::UpdateMouseCursor,
-			reinterpret_cast<const char *>(&pointingMouseCursor),
-			sizeof(pointingMouseCursor));
-	}
-
-	void updateVideoSize(quint32 videoSize)
-	{
-		writer->write(XineCommands::UpdateVideoSize,
-			reinterpret_cast<const char *>(&videoSize), sizeof(videoSize));
-	}
-
-	XinePipeWriterBase *writer;
-};
-
-#endif /* XINECOMMANDS_H */
diff --git a/src/backend-xine/xinemediawidget.cpp \
b/src/backend-xine/xinemediawidget.cpp deleted file mode 100644
index 960073e..0000000
--- a/src/backend-xine/xinemediawidget.cpp
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * xinemediawidget.cpp
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#include "xinemediawidget.h"
-#include "xinemediawidget_p.h"
-
-#include <QResizeEvent>
-#include <KMessageBox>
-#include <config-kaffeine.h>
-#include <errno.h>
-#include <unistd.h>
-#include "../log.h"
-
-static QString binInstallPath()
-{
-	return QString::fromUtf8(KAFFEINE_BIN_INSTALL_DIR "/");
-}
-
-XineProcess::XineProcess(XineMediaWidget *parent_) : QProcess(parent_), \
                parent(parent_)
-{
-	memset(pipeToChild, 0, sizeof(pipeToChild));
-	memset(pipeFromChild, 0, sizeof(pipeFromChild));
-
-	if ((pipe(pipeToChild) != 0) || (pipe(pipeFromChild) != 0)) {
-		Log("XineProcess::XineProcess: pipe failed");
-		reader = NULL;
-		writer = new XinePipeWriterBase();
-		childProcess.writer = writer;
-		return;
-	}
-
-	reader = new XinePipeReader(pipeFromChild[0], this);
-	writer = new XinePipeWriter(pipeToChild[1], this);
-	childProcess.writer = writer;
-
-	setProcessChannelMode(ForwardedChannels);
-	start(binInstallPath() + "kaffeine-xbu", QStringList() << "fU4eT3iN");
-}
-
-XineProcess::~XineProcess()
-{
-	if (state() != QProcess::NotRunning) {
-		childProcess.quit();
-
-		if (!waitForFinished(3000)) {
-			kill();
-		}
-	}
-
-	delete reader;
-	delete writer;
-}
-
-void XineProcess::readyRead()
-{
-	reader->readyRead();
-
-	while (true) {
-		int command = reader->nextCommand();
-
-		switch (command) {
-		case -1:
-			return;
-		case XineCommands::InitFailed: {
-			QString errorMessage = reader->readString();
-
-			if (reader->isValid()) {
-				parent->initFailed(errorMessage);
-			}
-
-			break;
-		    }
-		case XineCommands::Sync: {
-			quint32 sequenceNumber = reader->readInt();
-
-			if (reader->isValid()) {
-				parent->sync(sequenceNumber);
-			}
-
-			break;
-		    }
-		case XineCommands::PlaybackFailed: {
-			QString errorMessage = reader->readString();
-
-			if (reader->isValid()) {
-				parent->playbackFailed(errorMessage);
-			}
-
-			break;
-		    }
-		case XineCommands::PlaybackFinished:
-			parent->playbackFinishedInternal();
-			break;
-		case XineCommands::UpdateCurrentTotalTime: {
-			qint32 currentTime = reader->readInt();
-			qint32 totalTime = reader->readInt();
-
-			if (reader->isValid()) {
-				parent->updateCurrentTotalTime(currentTime, totalTime);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateMetadata: {
-			QString metadata = reader->readString();
-
-			if (reader->isValid()) {
-				parent->updateMetadata(metadata);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateSeekable: {
-			bool seekable = reader->readBool();
-
-			if (reader->isValid()) {
-				parent->updateSeekable(seekable);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateAudioChannels: {
-			qint8 currentAudioChannel = reader->readChar();
-			QByteArray audioChannels = reader->readByteArray();
-
-			if (reader->isValid()) {
-				parent->updateAudioChannels(audioChannels, currentAudioChannel);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateSubtitles: {
-			qint8 currentSubtitle = reader->readChar();
-			QByteArray subtitles = reader->readByteArray();
-
-			if (reader->isValid()) {
-				parent->updateSubtitles(subtitles, currentSubtitle);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateTitles: {
-			qint8 titleCount = reader->readChar();
-			qint8 currentTitle = reader->readChar();
-
-			if (reader->isValid()) {
-				parent->updateTitles(titleCount, currentTitle);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateChapters: {
-			qint8 chapterCount = reader->readChar();
-			qint8 currentChapter = reader->readChar();
-
-			if (reader->isValid()) {
-				parent->updateChapters(chapterCount, currentChapter);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateAngles: {
-			qint8 angleCount = reader->readChar();
-			qint8 currentAngle = reader->readChar();
-
-			if (reader->isValid()) {
-				parent->updateAngles(angleCount, currentAngle);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateMouseTracking: {
-			bool mouseTrackingEnabled = reader->readBool();
-
-			if (reader->isValid()) {
-				parent->updateMouseTracking(mouseTrackingEnabled);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateMouseCursor: {
-			bool pointingMouseCursor = reader->readBool();
-
-			if (reader->isValid()) {
-				parent->updateMouseCursor(pointingMouseCursor);
-			}
-
-			break;
-		    }
-		case XineCommands::UpdateVideoSize: {
-			quint32 videoSize = reader->readInt();
-
-			if (reader->isValid()) {
-				parent->updateVideoSize(videoSize);
-			}
-
-			break;
-		    }
-		default:
-			Log("XineProcess::readyRead: unknown command") << command;
-			continue;
-		}
-
-		if (!reader->isValid()) {
-			Log("XineProcess::readyRead: wrong argument size for command") << command;
-		}
-	}
-}
-
-void XineProcess::setupChildProcess()
-{
-	while (true) {
-		if (dup2(pipeToChild[0], 3) < 0) {
-			if (errno == EINTR) {
-				continue;
-			}
-
-			Log("XineProcess::setupChildProcess: dup2 failed");
-		}
-
-		break;
-	}
-
-	while (true) {
-		if (dup2(pipeFromChild[1], 4) < 0) {
-			if (errno == EINTR) {
-				continue;
-			}
-
-			Log("XineProcess::setupChildProcess: dup2 failed");
-		}
-
-		break;
-	}
-}
-
-XineMediaWidget::XineMediaWidget(QWidget *parent) : QWidget(parent), \
                sequenceNumber(0x71821680),
-	currentTime(0), totalTime(0), seekable(false), currentAudioChannel(-1),
-	currentSubtitle(-1), titleCount(0), currentTitle(0), chapterCount(0), \
                currentChapter(0),
-	angleCount(0), currentAngle(0), videoSize(0)
-{
-	setAttribute(Qt::WA_NativeWindow);
-	setAttribute(Qt::WA_PaintOnScreen);
-
-	QPalette palette = QWidget::palette();
-	palette.setColor(backgroundRole(), Qt::black);
-	setPalette(palette);
-	setAutoFillBackground(true);
-
-	process = new XineProcess(this);
-	childProcess = process->getChildProcess();
-	childProcess->init(winId());
-	hide();
-}
-
-XineMediaWidget::~XineMediaWidget()
-{
-}
-
-void XineMediaWidget::setMuted(bool muted)
-{
-	childProcess->setMuted(muted);
-}
-
-void XineMediaWidget::setVolume(int volume)
-{
-	childProcess->setVolume(volume);
-}
-
-void XineMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
-{
-	XineAspectRatio xineAspectRatio;
-
-	switch (aspectRatio) {
-	case MediaWidget::AspectRatioAuto:
-		xineAspectRatio = XineAspectRatioAuto;
-		break;
-	case MediaWidget::AspectRatio4_3:
-		xineAspectRatio = XineAspectRatio4_3;
-		break;
-	case MediaWidget::AspectRatio16_9:
-		xineAspectRatio = XineAspectRatio16_9;
-		break;
-	case MediaWidget::AspectRatioWidget:
-		xineAspectRatio = XineAspectRatioWidget;
-		break;
-	default:
-		Log("XineMediaWidget::setAspectRatio: unknown aspect ratio") << aspectRatio;
-		return;
-	}
-
-	childProcess->setAspectRatio(xineAspectRatio);
-}
-
-void XineMediaWidget::setDeinterlacing(bool deinterlacing)
-{
-	childProcess->setDeinterlacing(deinterlacing);
-}
-
-void XineMediaWidget::playUrl(const KUrl &url, const KUrl &subtitleUrl)
-{
-	if (url.toLocalFile().endsWith(QLatin1String(".iso"), Qt::CaseInsensitive)) {
-		currentUrl = QByteArray("dvd://").append(url.encodedPath());
-		playEncodedUrl(currentUrl, PlayingDvd);
-	} else {
-		currentUrl = url.toEncoded();
-		QByteArray encodedUrl = currentUrl;
-
-		if (subtitleUrl.isValid()) {
-			encodedUrl.append("#subtitle:");
-			encodedUrl.append(subtitleUrl.encodedPath());
-		}
-
-		playEncodedUrl(encodedUrl, EmitPlaybackFinished);
-	}
-}
-
-void XineMediaWidget::playAudioCd(const QString &device)
-{
-	currentUrl = QByteArray("cdda://").append(device.toUtf8().toPercentEncoding("/"));
-	playEncodedUrl(currentUrl);
-}
-
-void XineMediaWidget::playVideoCd(const QString &device)
-{
-	currentUrl = QByteArray("vcd://").append(device.toUtf8().toPercentEncoding("/"));
-	playEncodedUrl(currentUrl);
-}
-
-void XineMediaWidget::playDvd(const QString &device)
-{
-	currentUrl = QByteArray("dvd://").append(device.toUtf8().toPercentEncoding("/"));
-	playEncodedUrl(currentUrl, PlayingDvd);
-}
-
-void XineMediaWidget::setExternalSubtitle(const KUrl &subtitleUrl)
-{
-	QByteArray encodedUrl = currentUrl;
-	int position = currentTime;
-	int audioChannel = currentAudioChannel;
-
-	if (subtitleUrl.isValid()) {
-		encodedUrl.append("#subtitle:");
-		encodedUrl.append(subtitleUrl.encodedPath());
-	}
-
-	playEncodedUrl(encodedUrl, EmitPlaybackFinished);
-	seek(position);
-	setCurrentAudioChannel(audioChannel);
-}
-
-void XineMediaWidget::stop()
-{
-	currentUrl.clear();
-	playEncodedUrl(QByteArray());
-}
-
-bool XineMediaWidget::isPlaying() const
-{
-	return ((currentState & Playing) != 0);
-}
-
-bool XineMediaWidget::isSeekable() const
-{
-	return seekable;
-}
-
-int XineMediaWidget::getCurrentTime() const
-{
-	return currentTime;
-}
-
-int XineMediaWidget::getTotalTime() const
-{
-	return totalTime;
-}
-
-QStringList XineMediaWidget::getAudioChannels() const
-{
-	return audioChannels;
-}
-
-QStringList XineMediaWidget::getSubtitles() const
-{
-	return subtitles;
-}
-
-int XineMediaWidget::getCurrentAudioChannel() const
-{
-	return currentAudioChannel;
-}
-
-int XineMediaWidget::getCurrentSubtitle() const
-{
-	return currentSubtitle;
-}
-
-void XineMediaWidget::setPaused(bool paused)
-{
-	childProcess->setPaused(paused);
-}
-
-void XineMediaWidget::setCurrentAudioChannel(int currentAudioChannel_)
-{
-	childProcess->setCurrentAudioChannel(currentAudioChannel_);
-}
-
-void XineMediaWidget::setCurrentSubtitle(int currentSubtitle_)
-{
-	childProcess->setCurrentSubtitle(currentSubtitle_);
-}
-
-void XineMediaWidget::toggleMenu()
-{
-	childProcess->toggleMenu();
-}
-
-void XineMediaWidget::setCurrentTitle(int currentTitle_)
-{
-	if (currentUrl.startsWith("cdda:") || currentUrl.startsWith("dvd:")) {
-		QByteArray encodedUrl = currentUrl;
-
-		if (!encodedUrl.endsWith('/')) {
-			encodedUrl.append('/');
-		}
-
-		encodedUrl.append(QByteArray::number(currentTitle_));
-
-		if (currentUrl.startsWith("dvd:")) {
-			playEncodedUrl(encodedUrl, PlayingDvd);
-		} else {
-			playEncodedUrl(encodedUrl);
-		}
-	} else if (currentUrl.startsWith("vcd:")) {
-		playEncodedUrl(currentUrl + '@' + QByteArray::number(currentTitle_));
-	}
-}
-
-void XineMediaWidget::setCurrentChapter(int currentChapter_)
-{
-	if ((currentState & PlayingDvd) != 0) {
-		if (!encodedDvdUrl.endsWith('/')) {
-			encodedDvdUrl.append('/');
-		}
-
-		QByteArray encodedUrl = encodedDvdUrl;
-		encodedUrl.append(QByteArray::number(currentTitle));
-		encodedUrl.append('.');
-		encodedUrl.append(QByteArray::number(currentChapter_));
-		playEncodedUrl(encodedUrl, PlayingDvd);
-	}
-}
-
-void XineMediaWidget::setCurrentAngle(int currentAngle_)
-{
-	Q_UNUSED(currentAngle_) // not possible :-(
-}
-
-bool XineMediaWidget::playPreviousTitle()
-{
-	if (currentTitle > 1) {
-		setCurrentTitle(currentTitle - 1);
-		return true;
-	}
-
-	return false;
-}
-
-bool XineMediaWidget::playNextTitle()
-{
-	if (currentTitle < titleCount) {
-		setCurrentTitle(currentTitle + 1);
-		return true;
-	}
-
-	return false;
-}
-
-void XineMediaWidget::seek(int time)
-{
-	if (isPlaying() && (time != currentTime)) {
-		childProcess->seek(time);
-	}
-}
-
-void XineMediaWidget::mouseMoveEvent(QMouseEvent *event)
-{
-	QWidget::mouseMoveEvent(event);
-	childProcess->mouseMoved(event->x(), event->y());
-}
-
-void XineMediaWidget::mousePressEvent(QMouseEvent *event)
-{
-	QWidget::mousePressEvent(event);
-
-	if (event->button() == Qt::LeftButton) {
-		childProcess->mousePressed(event->x(), event->y());
-	}
-}
-
-void XineMediaWidget::paintEvent(QPaintEvent *event)
-{
-	QWidget::paintEvent(event);
-	childProcess->repaint();
-}
-
-void XineMediaWidget::resizeEvent(QResizeEvent *event)
-{
-	QWidget::resizeEvent(event);
-	childProcess->resize(event->size().width(), event->size().height());
-}
-
-QSize XineMediaWidget::sizeHint() const
-{
-	return QSize(videoSize >> 16, videoSize & 0xffff);
-}
-
-void XineMediaWidget::initFailed(const QString &errorMessage)
-{
-	if ((currentState & NotReady) == 0) {
-		currentUrl.clear();
-		playEncodedUrl(QByteArray(), NotReady);
-		KMessageBox::queuedMessageBox(this, KMessageBox::Sorry, errorMessage); // FIXME
-	}
-}
-
-void XineMediaWidget::sync(unsigned int sequenceNumber_)
-{
-	if ((sequenceNumber == sequenceNumber_) && isPlaying()) {
-		currentState |= Synchronized;
-	}
-}
-
-void XineMediaWidget::playbackFailed(const QString &errorMessage)
-{
-	if ((currentState & Synchronized) != 0) {
-		if ((currentState & PlayingDvd) != 0) {
-			dirtyFlags |= PlayingDvdChanged;
-		}
-
-		currentState = 0;
-		dirtyFlags |= (ResetState | PlaybackStopped | PlaybackChanged);
-		stateChanged();
-		KMessageBox::queuedMessageBox(this, KMessageBox::Sorry, errorMessage); // FIXME
-	}
-}
-
-void XineMediaWidget::playbackFinishedInternal()
-{
-	if ((currentState & Synchronized) != 0) {
-		if (currentUrl.startsWith("cdda") && (currentTitle < titleCount)) {
-			playNextTitle();
-			return;
-		}
-
-		if ((currentState & PlayingDvd) != 0) {
-			dirtyFlags |= PlayingDvdChanged;
-		}
-
-		if ((currentState & EmitPlaybackFinished) != 0) {
-			dirtyFlags |= PlaybackFinished;
-		} else {
-			dirtyFlags |= PlaybackStopped;
-		}
-
-		currentState = 0;
-		dirtyFlags |= (ResetState | PlaybackChanged);
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateCurrentTotalTime(int currentTime_, int totalTime_)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (currentTime_ < 0) {
-			currentTime_ = 0;
-		}
-
-		if (currentTime != currentTime_) {
-			currentTime = currentTime_;
-			dirtyFlags |= CurrentTimeChanged;
-		}
-
-		if (totalTime_ < currentTime) {
-			totalTime_ = currentTime;
-		}
-
-		if (totalTime != totalTime_) {
-			totalTime = totalTime_;
-			dirtyFlags |= TotalTimeChanged;
-		}
-
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateMetadata(const QString &metadata_)
-{
-	if (((currentState & Synchronized) != 0) && (rawMetadata != metadata_)) {
-		rawMetadata = metadata_;
-		metadata.clear();
-
-		for (int i = 0; i < rawMetadata.size(); ++i) {
-			int type = rawMetadata.at(i).unicode();
-			++i;
-			int end = i;
-
-			while ((end < rawMetadata.size()) && (rawMetadata.at(end) != '\0')) {
-				++end;
-			}
-
-			if (i == end) {
-				continue;
-			}
-
-			QString content = rawMetadata.mid(i, end - i);
-			i = end;
-
-			switch (type) {
-			case XineMetadataTitle:
-				metadata.insert(MediaWidget::Title, content);
-				break;
-			case XineMetadataArtist:
-				metadata.insert(MediaWidget::Artist, content);
-				break;
-			case XineMetadataAlbum:
-				metadata.insert(MediaWidget::Album, content);
-				break;
-			case XineMetadataTrackNumber:
-				metadata.insert(MediaWidget::TrackNumber, content);
-				break;
-			default:
-				Log("XineMediaWidget::updateMetadata: unknown metadata type") <<
-					type;
-				break;
-			}
-		}
-
-		dirtyFlags |= MetadataChanged;
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateSeekable(bool seekable_)
-{
-	if (((currentState & Synchronized) != 0) && (seekable != seekable_)) {
-		seekable = seekable_;
-		dirtyFlags |= SeekableChanged;
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateAudioChannels(const QByteArray &audioChannels_,
-	int currentAudioChannel_)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (rawAudioChannels != audioChannels_) {
-			rawAudioChannels = audioChannels_;
-			audioChannels.clear();
-			const char *rawData = rawAudioChannels.constData();
-
-			for (int i = 0; i < rawAudioChannels.size(); ++i) {
-				QString audioChannel = QString::fromLatin1(rawData + i);
-				i += audioChannel.size();
-
-				if (audioChannel.isEmpty()) {
-					audioChannel = QString::number(i + 1);
-				}
-
-				audioChannels.append(audioChannel);
-			}
-
-			dirtyFlags |= AudioChannelsChanged;
-		}
-
-		if ((currentAudioChannel_ < 0) || (currentAudioChannel_ >= audioChannels.size())) \
                {
-			currentAudioChannel_ = -1;
-		}
-
-		if (currentAudioChannel != currentAudioChannel_) {
-			currentAudioChannel = currentAudioChannel_;
-			dirtyFlags |= CurrentAudioChannelChanged;
-		}
-
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateSubtitles(const QByteArray &subtitles_, int \
                currentSubtitle_)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (rawSubtitles != subtitles_) {
-			rawSubtitles = subtitles_;
-			subtitles.clear();
-			const char *rawData = rawSubtitles.constData();
-
-			for (int i = 0; i < rawSubtitles.size(); ++i) {
-				QString subtitle = QString::fromLatin1(rawData + i);
-				i += subtitle.size();
-
-				if (subtitle.isEmpty()) {
-					subtitle = QString::number(i + 1);
-				}
-
-				subtitles.append(subtitle);
-			}
-
-			dirtyFlags |= SubtitlesChanged;
-		}
-
-		if ((currentSubtitle_ < 0) || (currentSubtitle_ >= subtitles.size())) {
-			currentSubtitle_ = -1;
-		}
-
-		if (currentSubtitle != currentSubtitle_) {
-			currentSubtitle = currentSubtitle_;
-			dirtyFlags |= CurrentSubtitleChanged;
-		}
-
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateTitles(int titleCount_, int currentTitle_)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (titleCount_ < 0) {
-			titleCount_ = 0;
-		}
-
-		if (titleCount != titleCount_) {
-			titleCount = titleCount_;
-			dirtyFlags |= TitleCountChanged;
-		}
-
-		if ((currentTitle_ < 0) || (currentTitle_ > titleCount)) {
-			currentTitle_ = 0;
-		}
-
-		if (currentTitle != currentTitle_) {
-			currentTitle = currentTitle_;
-			dirtyFlags |= CurrentTitleChanged;
-		}
-
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateChapters(int chapterCount_, int currentChapter_)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (chapterCount_ < 0) {
-			chapterCount_ = 0;
-		}
-
-		if (chapterCount != chapterCount_) {
-			chapterCount = chapterCount_;
-			dirtyFlags |= ChapterCountChanged;
-		}
-
-		if ((currentChapter_ < 0) || (currentChapter_ > chapterCount)) {
-			currentChapter_ = 0;
-		}
-
-		if (currentChapter != currentChapter_) {
-			currentChapter = currentChapter_;
-			dirtyFlags |= CurrentChapterChanged;
-		}
-
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateAngles(int angleCount_, int currentAngle_)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (angleCount_ < 0) {
-			angleCount_ = 0;
-		}
-
-		if (angleCount != angleCount_) {
-			angleCount = angleCount_;
-			dirtyFlags |= AngleCountChanged;
-		}
-
-		if ((currentAngle_ < 0) || (currentAngle_ > angleCount)) {
-			currentAngle_ = 0;
-		}
-
-		if (currentAngle != currentAngle_) {
-			currentAngle = currentAngle_;
-			dirtyFlags |= CurrentAngleChanged;
-		}
-
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::updateMouseTracking(bool mouseTrackingEnabled)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (mouseTrackingEnabled) {
-			setMouseTracking(true);
-		} else {
-			unsetCursor();
-			setMouseTracking(false);
-		}
-	}
-}
-
-void XineMediaWidget::updateMouseCursor(bool pointingMouseCursor)
-{
-	if ((currentState & Synchronized) != 0) {
-		if (pointingMouseCursor && hasMouseTracking()) {
-			setCursor(Qt::PointingHandCursor);
-		} else {
-			unsetCursor();
-		}
-	}
-}
-
-void XineMediaWidget::updateVideoSize(unsigned int videoSize_)
-{
-	if (((currentState & Synchronized) != 0) && (videoSize != videoSize_)) {
-		videoSize = videoSize_;
-		dirtyFlags |= VideoSizeChanged;
-		stateChanged();
-	}
-}
-
-void XineMediaWidget::playEncodedUrl(const QByteArray &encodedUrl, StateFlags \
                stateFlags)
-{
-	++sequenceNumber;
-	childProcess->playUrl(sequenceNumber, encodedUrl);
-
-	if (!encodedUrl.isEmpty() && ((currentState & NotReady) == 0)) {
-		stateFlags |= Playing;
-		dirtyFlags |= (SourceChanged | ResetState);
-	} else {
-		stateFlags = ((currentState | stateFlags) & NotReady);
-		dirtyFlags |= (PlaybackStopped | ResetState);
-	}
-
-	StateFlags difference = currentState ^ stateFlags;
-	currentState = stateFlags;
-
-	if ((difference & Playing) != 0) {
-		dirtyFlags |= PlaybackChanged;
-	}
-
-	if ((difference & PlayingDvd) != 0) {
-		dirtyFlags |= PlayingDvdChanged;
-	}
-
-	stateChanged();
-}
-
-void XineMediaWidget::stateChanged()
-{
-	while (dirtyFlags != 0) {
-		int lowestDirtyFlag = dirtyFlags & (~(dirtyFlags - 1));
-		dirtyFlags &= ~lowestDirtyFlag;
-
-		switch (lowestDirtyFlag) {
-		case ResetState:
-			if (currentTime != 0) {
-				currentTime = 0;
-				dirtyFlags |= CurrentTimeChanged;
-			}
-
-			if (totalTime != 0) {
-				totalTime = 0;
-				dirtyFlags |= TotalTimeChanged;
-			}
-
-			if (!metadata.isEmpty()) {
-				rawMetadata.clear();
-				metadata.clear();
-				dirtyFlags |= MetadataChanged;
-			}
-
-			if (seekable != isPlaying()) {
-				seekable = isPlaying();
-				dirtyFlags |= SeekableChanged;
-			}
-
-			if (!audioChannels.isEmpty()) {
-				rawAudioChannels.clear();
-				audioChannels.clear();
-				dirtyFlags |= AudioChannelsChanged;
-			}
-
-			if (currentAudioChannel != -1) {
-				currentAudioChannel = -1;
-				dirtyFlags |= CurrentAudioChannelChanged;
-			}
-
-			if (!subtitles.isEmpty()) {
-				rawSubtitles.clear();
-				subtitles.clear();
-				dirtyFlags |= SubtitlesChanged;
-			}
-
-			if (currentSubtitle != -1) {
-				currentSubtitle = -1;
-				dirtyFlags |= CurrentSubtitleChanged;
-			}
-
-			if ((currentState & PlayingDvd) == 0) {
-				encodedDvdUrl.clear();
-			}
-
-			if (titleCount != 0) {
-				titleCount = 0;
-				dirtyFlags |= TitleCountChanged;
-			}
-
-			if (currentTitle != 0) {
-				currentTitle = 0;
-				dirtyFlags |= CurrentTitleChanged;
-			}
-
-			if (chapterCount != 0) {
-				chapterCount = 0;
-				dirtyFlags |= ChapterCountChanged;
-			}
-
-			if (currentChapter != 0) {
-				currentChapter = 0;
-				dirtyFlags |= CurrentChapterChanged;
-			}
-
-			if (angleCount != 0) {
-				angleCount = 0;
-				dirtyFlags |= AngleCountChanged;
-			}
-
-			if (currentAngle != 0) {
-				currentAngle = 0;
-				dirtyFlags |= CurrentAngleChanged;
-			}
-
-			unsetCursor();
-			setMouseTracking(false);
-			break;
-		case SourceChanged:
-			emit sourceChanged();
-			break;
-		case PlaybackFinished:
-			emit playbackFinished();
-			break;
-		case PlaybackStopped:
-			emit playbackStopped();
-			break;
-		case PlaybackChanged:
-			if (isPlaying()) {
-				show();
-				emit playbackChanged(true);
-			} else {
-				hide();
-				parentWidget()->update();
-				emit playbackChanged(false);
-			}
-
-			break;
-		case TotalTimeChanged:
-			emit totalTimeChanged(totalTime);
-			break;
-		case CurrentTimeChanged:
-			emit currentTimeChanged(currentTime);
-			break;
-		case MetadataChanged:
-			emit metadataChanged(metadata);
-			break;
-		case SeekableChanged:
-			emit seekableChanged(seekable);
-			break;
-		case AudioChannelsChanged:
-			emit audioChannelsChanged(audioChannels, currentAudioChannel);
-			dirtyFlags &= ~CurrentAudioChannelChanged;
-			break;
-		case CurrentAudioChannelChanged:
-			emit currentAudioChannelChanged(currentAudioChannel);
-			break;
-		case SubtitlesChanged:
-			emit subtitlesChanged(subtitles, currentSubtitle);
-			dirtyFlags &= ~CurrentSubtitleChanged;
-			break;
-		case CurrentSubtitleChanged:
-			emit currentSubtitleChanged(currentSubtitle);
-			break;
-		case PlayingDvdChanged:
-			emit dvdPlaybackChanged((currentState & PlayingDvd) != 0);
-			break;
-		case TitleCountChanged:
-			emit titlesChanged(titleCount, currentTitle);
-			dirtyFlags &= ~CurrentTitleChanged;
-			break;
-		case CurrentTitleChanged:
-			emit currentTitleChanged(currentTitle);
-			break;
-		case ChapterCountChanged:
-			emit chaptersChanged(chapterCount, currentChapter);
-			dirtyFlags &= ~CurrentChapterChanged;
-			break;
-		case CurrentChapterChanged:
-			emit currentChapterChanged(currentChapter);
-			break;
-		case AngleCountChanged:
-			emit anglesChanged(angleCount, currentAngle);
-			dirtyFlags &= ~CurrentAngleChanged;
-			break;
-		case CurrentAngleChanged:
-			emit currentAngleChanged(currentAngle);
-			break;
-		case VideoSizeChanged:
-			updateGeometry();
-			emit videoSizeChanged();
-			break;
-		default:
-			Log("XineMediaWidget::stateChanged: unknown flag") << lowestDirtyFlag;
-			break;
-		}
-	}
-}
diff --git a/src/backend-xine/xinemediawidget.h b/src/backend-xine/xinemediawidget.h
deleted file mode 100644
index d7423f2..0000000
--- a/src/backend-xine/xinemediawidget.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * xinemediawidget.h
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#ifndef XINEMEDIAWIDGET_H
-#define XINEMEDIAWIDGET_H
-
-#include "../mediawidget.h"
-
-class XineChildMarshaller;
-class XineProcess;
-
-class XineMediaWidget : public QWidget
-{
-	friend class XineProcess;
-	Q_OBJECT
-public:
-	explicit XineMediaWidget(QWidget *parent);
-	~XineMediaWidget();
-
-	void setMuted(bool muted);
-	void setVolume(int volume); // [0 - 100]
-	void setAspectRatio(MediaWidget::AspectRatio aspectRatio);
-	void setDeinterlacing(bool deinterlacing);
-
-	void playUrl(const KUrl &url, const KUrl &subtitleUrl);
-	void playAudioCd(const QString &device);
-	void playVideoCd(const QString &device);
-	void playDvd(const QString &device);
-	void setExternalSubtitle(const KUrl &subtitleUrl);
-	void stop();
-
-	bool isPlaying() const;
-	bool isSeekable() const;
-	int getCurrentTime() const; // milliseconds
-	int getTotalTime() const; // milliseconds
-	QStringList getAudioChannels() const;
-	QStringList getSubtitles() const;
-	int getCurrentAudioChannel() const; // first audio channel = 0
-	int getCurrentSubtitle() const; // first subtitle = 0
-
-	void setPaused(bool paused);
-	void setCurrentAudioChannel(int currentAudioChannel_);
-	void setCurrentSubtitle(int currentSubtitle_);
-	void toggleMenu();
-	void setCurrentTitle(int currentTitle_); // first title = 1
-	void setCurrentChapter(int currentChapter_); // first chapter = 1
-	void setCurrentAngle(int currentAngle_); // first angle = 1
-	bool playPreviousTitle();
-	bool playNextTitle();
-
-public slots:
-	void seek(int time);
-
-signals:
-	void sourceChanged();
-	void playbackFinished();
-	void playbackStopped();
-	void playbackChanged(bool playing);
-	void totalTimeChanged(int totalTime);
-	void currentTimeChanged(int currentTime);
-	void metadataChanged(const QMap<MediaWidget::MetadataType, QString> &metadata);
-	void seekableChanged(bool seekable);
-	void audioChannelsChanged(const QStringList &audioChannels, int \
                currentAudioChannel);
-	void currentAudioChannelChanged(int currentAudioChannel);
-	void subtitlesChanged(const QStringList &subtitles, int currentSubtitle);
-	void currentSubtitleChanged(int currentSubtitle);
-	void dvdPlaybackChanged(bool playingDvd);
-	void titlesChanged(int titleCount, int currentTitle);
-	void currentTitleChanged(int currentTitle);
-	void chaptersChanged(int chapterCount, int currentChapter);
-	void currentChapterChanged(int currentChapter);
-	void anglesChanged(int angleCount, int currentAngle);
-	void currentAngleChanged(int currentAngle);
-	void videoSizeChanged();
-
-public:
-	enum StateFlag {
-		NotReady			= (1 << 0),
-		Playing				= (1 << 1),
-		PlayingDvd			= (1 << 2),
-		EmitPlaybackFinished		= (1 << 3),
-		Synchronized			= (1 << 4)
-	};
-
-	Q_DECLARE_FLAGS(StateFlags, StateFlag)
-
-	enum DirtyFlag {
-		ResetState			= (1 <<  0),
-		SourceChanged			= (1 <<  1),
-		PlaybackFinished		= (1 <<  2),
-		PlaybackStopped			= (1 <<  3),
-		PlaybackChanged			= (1 <<  4),
-		TotalTimeChanged		= (1 <<  5),
-		CurrentTimeChanged		= (1 <<  6),
-		MetadataChanged			= (1 <<  7),
-		SeekableChanged			= (1 <<  8),
-		AudioChannelsChanged		= (1 <<  9),
-		CurrentAudioChannelChanged	= (1 << 10),
-		SubtitlesChanged		= (1 << 11),
-		CurrentSubtitleChanged		= (1 << 12),
-		PlayingDvdChanged		= (1 << 13),
-		TitleCountChanged		= (1 << 14),
-		CurrentTitleChanged		= (1 << 15),
-		ChapterCountChanged		= (1 << 16),
-		CurrentChapterChanged		= (1 << 17),
-		AngleCountChanged		= (1 << 18),
-		CurrentAngleChanged		= (1 << 19),
-		VideoSizeChanged		= (1 << 20)
-	};
-
-	Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
-
-private:
-	void mouseMoveEvent(QMouseEvent *event);
-	void mousePressEvent(QMouseEvent *event);
-	void paintEvent(QPaintEvent *event);
-	void resizeEvent(QResizeEvent *event);
-	QSize sizeHint() const;
-
-	void initFailed(const QString &errorMessage);
-	void sync(unsigned int sequenceNumber_);
-	void playbackFailed(const QString &errorMessage);
-	void playbackFinishedInternal();
-	void updateCurrentTotalTime(int currentTime_, int totalTime_);
-	void updateMetadata(const QString &metadata_);
-	void updateSeekable(bool seekable_);
-	void updateAudioChannels(const QByteArray &audioChannels_, int \
                currentAudioChannel_);
-	void updateSubtitles(const QByteArray &subtitles_, int currentSubtitle_);
-	void updateTitles(int titleCount_, int currentTitle_);
-	void updateChapters(int chapterCount_, int currentChapter_);
-	void updateAngles(int angleCount_, int currentAngle_);
-	void updateMouseTracking(bool mouseTrackingEnabled);
-	void updateMouseCursor(bool pointingMouseCursor);
-	void updateVideoSize(unsigned int videoSize_);
-
-	void playEncodedUrl(const QByteArray &encodedUrl, StateFlags stateFlags = 0);
-	void stateChanged();
-
-	XineProcess *process;
-	XineChildMarshaller *childProcess;
-	StateFlags currentState;
-	DirtyFlags dirtyFlags;
-	QByteArray currentUrl;
-	unsigned int sequenceNumber;
-	int currentTime;
-	int totalTime;
-	QString rawMetadata;
-	QMap<MediaWidget::MetadataType, QString> metadata;
-	bool seekable;
-	QByteArray rawAudioChannels;
-	QStringList audioChannels;
-	int currentAudioChannel;
-	QByteArray rawSubtitles;
-	QStringList subtitles;
-	int currentSubtitle;
-	QByteArray encodedDvdUrl;
-	int titleCount;
-	int currentTitle;
-	int chapterCount;
-	int currentChapter;
-	int angleCount;
-	int currentAngle;
-	unsigned int videoSize;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(XineMediaWidget::StateFlags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(XineMediaWidget::DirtyFlags)
-
-#endif /* XINEMEDIAWIDGET_H */
diff --git a/src/backend-xine/xinemediawidget_p.h \
b/src/backend-xine/xinemediawidget_p.h deleted file mode 100644
index 5512779..0000000
--- a/src/backend-xine/xinemediawidget_p.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * xinemediawidget_p.h
- *
- * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
- *
- * 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.
- */
-
-#ifndef XINEMEDIAWIDGET_P_H
-#define XINEMEDIAWIDGET_P_H
-
-#include <QProcess>
-#include "xinecommands.h"
-
-class XineMediaWidget;
-
-class XineProcess : public QProcess
-{
-	Q_OBJECT
-public:
-	explicit XineProcess(XineMediaWidget *parent_);
-	~XineProcess();
-
-	XineChildMarshaller *getChildProcess()
-	{
-		return &childProcess;
-	}
-
-private slots:
-	void readyRead();
-
-private:
-	void setupChildProcess();
-
-	XineMediaWidget *parent;
-	int pipeToChild[2];
-	int pipeFromChild[2];
-	XinePipeReader *reader;
-	XinePipeWriterBase *writer;
-	XineChildMarshaller childProcess;
-};
-
-#endif /* XINEMEDIAWIDGET_P_H */
diff --git a/src/dbusobjects.cpp b/src/dbusobjects.cpp
index d6643b4..ba46b80 100644
--- a/src/dbusobjects.cpp
+++ b/src/dbusobjects.cpp
@@ -153,13 +153,18 @@ void MprisPlayerObject::Repeat(bool repeat)
 MprisStatusStruct MprisPlayerObject::GetStatus()
 {
 	MprisStatusStruct statusStruct;
+	statusStruct.state = 0;
 
-	if (mediaWidget->isPaused()) {
-		statusStruct.state = 1;
-	} else if (mediaWidget->isPlaying()) {
-		statusStruct.state = 0;
-	} else {
+	switch (mediaWidget->getPlaybackStatus()) {
+	case MediaWidget::Idle:
 		statusStruct.state = 2;
+		break;
+	case MediaWidget::Playing:
+		statusStruct.state = 0;
+		break;
+	case MediaWidget::Paused:
+		statusStruct.state = 1;
+		break;
 	}
 
 	if (playlistTab->getRandom()) {
@@ -192,8 +197,13 @@ int MprisPlayerObject::GetCaps()
 			   (1 << 4) | // CAN_SEEK // FIXME check availability
 			   (1 << 6);  // CAN_HAS_TRACKLIST
 
-	if (mediaWidget->isPlaying()) {
+	switch (mediaWidget->getPlaybackStatus()) {
+	case MediaWidget::Idle:
+		break;
+	case MediaWidget::Playing:
+	case MediaWidget::Paused:
 		capabilities |= (1 << 2); // CAN_PAUSE
+		break;
 	}
 
 	return capabilities; // FIXME metadata handling not implemented yet
diff --git a/src/dbusobjects.h b/src/dbusobjects.h
index 1745e23..797ae3d 100644
--- a/src/dbusobjects.h
+++ b/src/dbusobjects.h
@@ -130,6 +130,10 @@ private:
 	PlaylistTab *playlistTab;
 };
 
+#ifndef HAVE_DVB
+#error HAVE_DVB must be defined
+#endif /* HAVE_DVB */
+
 #if HAVE_DVB == 1
 
 class DBusTelevisionObject : public QObject
diff --git a/src/dvb/dvbliveview.cpp b/src/dvb/dvbliveview.cpp
index 3bec59e..5a63789 100644
--- a/src/dvb/dvbliveview.cpp
+++ b/src/dvb/dvbliveview.cpp
@@ -24,8 +24,15 @@
 #include <QDir>
 #include <QPainter>
 #include <QSet>
+#include <QSocketNotifier>
 #include <KLocale>
 #include <KMessageBox>
+#include <KStandardDirs>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h> // bsd compatibility
+#include <sys/types.h> // bsd compatibility
+#include <unistd.h>
 #include "../log.h"
 #include "../mediawidget.h"
 #include "dvbdevice.h"
@@ -127,24 +134,6 @@ QPixmap DvbOsd::paintOsd(QRect &rect, const QFont &font, \
Qt::LayoutDirection)  return pixmap;
 }
 
-void DvbLiveViewInternal::processData(const char data[188])
-{
-	buffer.append(data, 188);
-
-	if (buffer.size() < (87 * 188)) {
-		return;
-	}
-
-	if (!timeShiftFile.isOpen()) {
-		mediaWidget->writeDvbData(buffer);
-	} else {
-		timeShiftFile.write(buffer); // FIXME avoid buffer reallocation
-	}
-
-	buffer.clear();
-	buffer.reserve(87 * 188);
-}
-
 DvbLiveView::DvbLiveView(DvbManager *manager_, QObject *parent) : QObject(parent),
 	manager(manager_), device(NULL), videoPid(-1), audioPid(-1), subtitlePid(-1)
 {
@@ -159,11 +148,11 @@ DvbLiveView::DvbLiveView(DvbManager *manager_, QObject *parent) \
: QObject(parent  connect(&patPmtTimer, SIGNAL(timeout()), this, \
SLOT(insertPatPmt()));  connect(&osdTimer, SIGNAL(timeout()), this, \
SLOT(osdTimeout()));  
-	connect(mediaWidget, SIGNAL(changeDvbAudioChannel(int)),
+	connect(mediaWidget, SIGNAL(dvbSetCurrentAudioChannel(int)),
 		this, SLOT(changeAudioStream(int)));
-	connect(mediaWidget, SIGNAL(changeDvbSubtitle(int)), this, \
                SLOT(changeSubtitle(int)));
-	connect(mediaWidget, SIGNAL(prepareDvbTimeShift()), this, \
                SLOT(prepareTimeShift()));
-	connect(mediaWidget, SIGNAL(startDvbTimeShift()), this, SLOT(startTimeShift()));
+	connect(mediaWidget, SIGNAL(dvbSetCurrentSubtitle(int)), this, \
SLOT(changeSubtitle(int))); +	connect(mediaWidget, SIGNAL(dvbPrepareTimeShift()), \
this, SLOT(prepareTimeShift())); +	connect(mediaWidget, SIGNAL(dvbStartTimeShift()), \
this, SLOT(startTimeShift()));  connect(mediaWidget, SIGNAL(dvbStopped()), this, \
SLOT(liveStopped()));  }
 
@@ -216,7 +205,8 @@ void DvbLiveView::playChannel(const DvbSharedChannel &channel_)
 		return;
 	}
 
-	mediaWidget->playDvb(channel->name);
+	internal->channelName = channel->name;
+	mediaWidget->playDvb(MediaWidget::Dvb, internal->setupPipe(), channel->name);
 
 	internal->pmtFilter.setProgramNumber(channel->serviceId);
 	startDevice();
@@ -416,7 +406,8 @@ void DvbLiveView::prepareTimeShift()
 
 void DvbLiveView::startTimeShift()
 {
-	mediaWidget->play(internal->timeShiftFile.fileName());
+	mediaWidget->playDvb(MediaWidget::DvbTimeShift, internal->timeShiftFile.fileName(),
+		internal->channelName);
 }
 
 void DvbLiveView::showOsd()
@@ -544,3 +535,113 @@ void DvbLiveView::updatePids(bool forcePatPmtUpdate)
 		insertPatPmt();
 	}
 }
+
+DvbLiveViewInternal::DvbLiveViewInternal() : mediaWidget(NULL), readFd(-1), \
writeFd(-1) +{
+	QString fileName = KStandardDirs::locateLocal("appdata", "dvbpipe.m2t");
+	QFile::remove(fileName);
+	url = KUrl::fromLocalFile(fileName);
+	url.setScheme("fifo");
+
+	if (mkfifo(QFile::encodeName(fileName).constData(), 0600) != 0) {
+		Log("timeShiftActive: mkfifo failed");
+		return;
+	}
+
+	readFd = open(QFile::encodeName(fileName).constData(), O_RDONLY | O_NONBLOCK);
+
+	if (readFd < 0) {
+		Log("timeShiftActive: open failed");
+		return;
+	}
+
+	writeFd = open(QFile::encodeName(fileName).constData(), O_WRONLY | O_NONBLOCK);
+
+	if (writeFd < 0) {
+		Log("timeShiftActive: open failed");
+		return;
+	}
+
+	notifier = new QSocketNotifier(writeFd, QSocketNotifier::Write, this);
+	notifier->setEnabled(false);
+	connect(notifier, SIGNAL(activated(int)), this, SLOT(writeToPipe()));
+}
+
+DvbLiveViewInternal::~DvbLiveViewInternal()
+{
+	if (writeFd >= 0) {
+		close(writeFd);
+	}
+
+	if (readFd >= 0) {
+		close(readFd);
+	}
+}
+
+KUrl DvbLiveViewInternal::setupPipe()
+{
+	if (!buffers.isEmpty()) {
+		buffer = buffers.at(0);
+		buffers.clear();
+	}
+
+	if (readFd >= 0) {
+		if (buffer.isEmpty()) {
+			buffer.resize(87 * 188);
+		}
+
+		while (read(readFd, buffer.data(), buffer.size()) != 0) {
+		}
+	}
+
+	buffer.clear();
+	return url;
+}
+
+void DvbLiveViewInternal::writeToPipe()
+{
+	while (!buffers.isEmpty()) {
+		const QByteArray &buffer = buffers.at(0);
+		int bytesWritten = write(writeFd, buffer.constData(), buffer.size());
+
+		if ((bytesWritten < 0) && (errno == EINTR)) {
+			continue;
+		}
+
+		if (bytesWritten == buffer.size()) {
+			buffers.removeFirst();
+			continue;
+		}
+
+		if (bytesWritten > 0) {
+			buffers.first().remove(0, bytesWritten);
+		}
+
+		break;
+	}
+
+	if (!buffers.isEmpty()) {
+		notifier->setEnabled(true);
+	}
+}
+
+void DvbLiveViewInternal::processData(const char data[188])
+{
+	buffer.append(data, 188);
+
+	if (buffer.size() < (87 * 188)) {
+		return;
+	}
+
+	if (!timeShiftFile.isOpen()) {
+		if (writeFd >= 0) {
+			buffers.append(buffer);
+			writeToPipe();
+		}
+	} else {
+		timeShiftFile.write(buffer); // FIXME avoid buffer reallocation
+	}
+
+	buffer.clear();
+	buffer.reserve(87 * 188);
+}
diff --git a/src/dvb/dvbliveview_p.h b/src/dvb/dvbliveview_p.h
index 9066b1c..0a52f76 100644
--- a/src/dvb/dvbliveview_p.h
+++ b/src/dvb/dvbliveview_p.h
@@ -22,10 +22,12 @@
 #define DVBLIVEVIEW_P_H
 
 #include <QFile>
+#include <KUrl>
 #include "../osdwidget.h"
 #include "dvbepg.h"
 #include "dvbsi.h"
 
+class QSocketNotifier;
 class MediaWidget;
 
 class DvbOsd : public OsdObject
@@ -53,13 +55,17 @@ private:
 	DvbEpgEntry secondEntry;
 };
 
-class DvbLiveViewInternal : public DvbPidFilter
+class DvbLiveViewInternal : public QObject, public DvbPidFilter
 {
+	Q_OBJECT
 public:
-	DvbLiveViewInternal() : mediaWidget(NULL) { }
-	~DvbLiveViewInternal() { }
+	DvbLiveViewInternal();
+	~DvbLiveViewInternal();
+
+	KUrl setupPipe();
 
 	MediaWidget *mediaWidget;
+	QString channelName;
 	DvbPmtFilter pmtFilter;
 	QByteArray pmtSectionData;
 	DvbSectionGenerator patGenerator;
@@ -68,8 +74,17 @@ public:
 	QFile timeShiftFile;
 	DvbOsd dvbOsd;
 
+private slots:
+	void writeToPipe();
+
 private:
 	void processData(const char data[188]);
+
+	KUrl url;
+	int readFd;
+	int writeFd;
+	QSocketNotifier *notifier;
+	QList<QByteArray> buffers;
 };
 
 #endif /* DVBLIVEVIEW_P_H */
diff --git a/src/dvb/dvbtab.cpp b/src/dvb/dvbtab.cpp
index e07c318..0eb2ae6 100644
--- a/src/dvb/dvbtab.cpp
+++ b/src/dvb/dvbtab.cpp
@@ -119,8 +119,8 @@ DvbTab::DvbTab(KMenu *menu, KActionCollection *collection, \
MediaWidget *mediaWid  connect(configureAction, SIGNAL(triggered()), this, \
SLOT(configureDvb()));  menu->addAction(collection->addAction("settings_dvb", \
configureAction));  
-	connect(mediaWidget, SIGNAL(previousDvbChannel()), this, SLOT(previousChannel()));
-	connect(mediaWidget, SIGNAL(nextDvbChannel()), this, SLOT(nextChannel()));
+	connect(mediaWidget, SIGNAL(dvbPreviousChannel()), this, SLOT(previousChannel()));
+	connect(mediaWidget, SIGNAL(dvbNextChannel()), this, SLOT(nextChannel()));
 
 	connect(manager->getRecordingModel(), SIGNAL(recordingRemoved(DvbSharedRecording)),
 		this, SLOT(recordingRemoved(DvbSharedRecording)));
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 43dd014..3e33456 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -253,7 +253,8 @@ MainWindow::MainWindow()
 	mediaWidget = new MediaWidget(playerMenu, controlBar, collection, widget);
 	connect(mediaWidget, SIGNAL(displayModeChanged()), this, \
SLOT(displayModeChanged()));  connect(mediaWidget, SIGNAL(changeCaption(QString)), \
                this, SLOT(setCaption(QString)));
-	connect(mediaWidget, SIGNAL(resizeToVideo(int)), this, SLOT(resizeToVideo(int)));
+	connect(mediaWidget, SIGNAL(resizeToVideo(MediaWidget::ResizeFactor)),
+		this, SLOT(resizeToVideo(MediaWidget::ResizeFactor)));
 
 	// tabs - keep in sync with TabIndex enum!
 
@@ -590,14 +591,29 @@ void MainWindow::playDvb()
 	dvbTab->playLastChannel();
 }
 
-void MainWindow::resizeToVideo(int factor)
+void MainWindow::resizeToVideo(MediaWidget::ResizeFactor resizeFactor)
 {
 	if (!isFullScreen() && !mediaWidget->sizeHint().isEmpty()) {
 		if (isMaximized()) {
 			setWindowState(windowState() & ~Qt::WindowMaximized);
 		}
 
-		resize(size() - centralWidget()->size() + factor * mediaWidget->sizeHint());
+		QSize videoSize;
+
+		switch (resizeFactor) {
+		case MediaWidget::ResizeOff:
+			break;
+		case MediaWidget::OriginalSize:
+			videoSize = mediaWidget->sizeHint();
+			break;
+		case MediaWidget::DoubleSize:
+			videoSize = (2 * mediaWidget->sizeHint());
+			break;
+		}
+
+		if (!videoSize.isEmpty()) {
+			resize(size() - centralWidget()->size() + videoSize);
+		}
 	}
 }
 
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 87ccbd3..5bddb60 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -22,6 +22,7 @@
 #define MAINWINDOW_H
 
 #include <KMainWindow>
+#include "mediawidget.h"
 
 class QStackedLayout;
 class KActionCollection;
@@ -58,7 +59,7 @@ private slots:
 	void openDvd(const QString &device = QString());
 	void playDvdFolder();
 	void playDvb();
-	void resizeToVideo(int factor);
+	void resizeToVideo(MediaWidget::ResizeFactor resizeFactor);
 	void configureKeys();
 	void configureKaffeine();
 	void navigationBarOrientationChanged(Qt::Orientation orientation);
diff --git a/src/mediawidget.cpp b/src/mediawidget.cpp
index f348a11..7a3bb43 100644
--- a/src/mediawidget.cpp
+++ b/src/mediawidget.cpp
@@ -24,10 +24,8 @@
 #include <QBoxLayout>
 #include <QContextMenuEvent>
 #include <QDBusInterface>
-#include <QFile>
 #include <QLabel>
 #include <QPushButton>
-#include <QSocketNotifier>
 #include <QTimeEdit>
 #include <QTimer>
 #include <QX11Info>
@@ -38,199 +36,46 @@
 #include <KComboBox>
 #include <KLocalizedString>
 #include <KMenu>
-#include <KStandardDirs>
 #include <KToolBar>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h> // bsd compatibility
-#include <sys/types.h> // bsd compatibility
-#include <unistd.h>
 #include <X11/extensions/scrnsaver.h>
-#include "backend-xine/xinemediawidget.h"
+#include "backend-vlc/vlcmediawidget.h"
 #include "configuration.h"
 #include "log.h"
 #include "osdwidget.h"
 
-DvbFeed::DvbFeed(QObject *parent) : QObject(parent), timeShiftPrepared(false),
-	timeShiftActive(false), ignoreSourceChange(false), readFd(-1), writeFd(-1), \
                notifier(NULL)
-{
-	QString fileName = KStandardDirs::locateLocal("appdata", "dvbpipe.m2t");
-	QFile::remove(fileName);
-	url = KUrl::fromLocalFile(fileName);
-	url.setScheme("fifo");
-
-	if (mkfifo(QFile::encodeName(fileName).constData(), 0600) != 0) {
-		Log("timeShiftActive: mkfifo failed");
-		return;
-	}
-
-	readFd = open(QFile::encodeName(fileName).constData(), O_RDONLY | O_NONBLOCK);
-
-	if (readFd < 0) {
-		Log("timeShiftActive: open failed");
-		return;
-	}
-
-	writeFd = open(QFile::encodeName(fileName).constData(), O_WRONLY | O_NONBLOCK);
-
-	if (writeFd < 0) {
-		Log("timeShiftActive: open failed");
-		close(readFd);
-		readFd = -1;
-	}
-
-	notifier = new QSocketNotifier(writeFd, QSocketNotifier::Write, this);
-	notifier->setEnabled(false);
-	connect(notifier, SIGNAL(activated(int)), this, SLOT(readyWrite()));
-}
-
-DvbFeed::~DvbFeed()
-{
-	endOfData();
-}
-
-KUrl DvbFeed::getUrl() const
-{
-	return url;
-}
-
-void DvbFeed::writeData(const QByteArray &data)
-{
-	if (writeFd >= 0) {
-		buffers.append(data);
-
-		if (!flush()) {
-			notifier->setEnabled(true);
-		}
-	}
-}
-
-void DvbFeed::endOfData()
-{
-	if (writeFd >= 0) {
-		notifier->setEnabled(false);
-		close(writeFd);
-		writeFd = -1;
-	}
-
-	if (readFd >= 0) {
-		close(readFd);
-		readFd = -1;
-	}
-}
-
-void DvbFeed::readyWrite()
-{
-	if (flush()) {
-		notifier->setEnabled(false);
-	}
-}
-
-bool DvbFeed::flush()
-{
-	while (!buffers.isEmpty()) {
-		const QByteArray &buffer = *buffers.constBegin();
-		int bytesWritten = write(writeFd, buffer.constData(), buffer.size());
-
-		if ((bytesWritten < 0) && (errno == EINTR)) {
-			continue;
-		}
-
-		if (bytesWritten == buffer.size()) {
-			buffers.removeFirst();
-			continue;
-		}
-
-		if (bytesWritten > 0) {
-			buffers.first().remove(0, bytesWritten);
-		}
-
-		break;
-	}
-
-	return buffers.isEmpty();
-}
-
-JumpToPositionDialog::JumpToPositionDialog(MediaWidget *mediaWidget_) : \
                KDialog(mediaWidget_),
-	mediaWidget(mediaWidget_)
-{
-	setCaption(i18nc("@title:window", "Jump to Position"));
-
-	QWidget *widget = new QWidget(this);
-	QBoxLayout *layout = new QVBoxLayout(widget);
-
-	layout->addWidget(new QLabel(i18n("Enter a position:")));
-
-	timeEdit = new QTimeEdit(this);
-	timeEdit->setDisplayFormat("hh:mm:ss");
-	timeEdit->setTime(QTime().addSecs(mediaWidget->getPosition() / 1000));
-	layout->addWidget(timeEdit);
-
-	timeEdit->setFocus();
-
-	setMainWidget(widget);
-}
-
-JumpToPositionDialog::~JumpToPositionDialog()
-{
-}
-
-void JumpToPositionDialog::accept()
-{
-	mediaWidget->setPosition(QTime().msecsTo(timeEdit->time()));
-	KDialog::accept();
-}
-
-void SeekSlider::mousePressEvent(QMouseEvent *event)
-{
-	int buttons = style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons);
-	Qt::MouseButton button = static_cast<Qt::MouseButton>(buttons & (~(buttons - 1)));
-	QMouseEvent modifiedEvent(event->type(), event->pos(), event->globalPos(), button,
-		event->buttons() ^ event->button() ^ button, event->modifiers());
-	QSlider::mousePressEvent(&modifiedEvent);
-}
-
 MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, KActionCollection \
                *collection,
-	QWidget *parent) : QWidget(parent), menu(menu_), dvbFeed(NULL), \
screenSaverSuspended(false) +	QWidget *parent) : QWidget(parent), menu(menu_),
+	backendPlaybackStatus(Idle), displayMode(NormalMode), automaticResize(ResizeOff), \
source(Playlist), blockBackendUpdates(false), muted(false), \
screenSaverSuspended(false), backendTotalTime(0), backendCurrentTime(0), \
showElapsedTime(true), backendSeekable(false), currentBackendAudioChannel(-1), \
currentDvbAudioChannel(-1), currentBackendSubtitle(-1), currentDvbSubtitle(-1), \
currentExternalSubtitle(-1)  {
 	QBoxLayout *layout = new QVBoxLayout(this);
 	layout->setMargin(0);
 
-	setAcceptDrops(true);
-	setFocusPolicy(Qt::StrongFocus);
-
 	QPalette palette = QWidget::palette();
 	palette.setColor(backgroundRole(), Qt::black);
 	setPalette(palette);
 	setAutoFillBackground(true);
 
-	backend = new XineMediaWidget(this);
-	connect(backend, SIGNAL(sourceChanged()), this, SLOT(sourceChanged()));
+	setAcceptDrops(true);
+	setFocusPolicy(Qt::StrongFocus);
+
+	backend = AbstractMediaWidget::createVlcMediaWidget(this);
 	connect(backend, SIGNAL(playbackFinished()), this, SLOT(playbackFinished()));
-	connect(backend, SIGNAL(playbackStopped()), this, SLOT(playbackStopped()));
-	connect(backend, SIGNAL(playbackChanged(bool)), this, SLOT(playbackChanged(bool)));
-	connect(backend, SIGNAL(totalTimeChanged(int)), this, SLOT(totalTimeChanged(int)));
-	connect(backend, SIGNAL(currentTimeChanged(int)), this, \
                SLOT(currentTimeChanged(int)));
-	connect(backend, SIGNAL(metadataChanged(QMap<MediaWidget::MetadataType,QString>)),
-		this, SLOT(setMetadata(QMap<MediaWidget::MetadataType,QString>)));
-	connect(backend, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
-	connect(backend, SIGNAL(audioChannelsChanged(QStringList,int)),
-		this, SLOT(audioChannelsChanged(QStringList,int)));
-	connect(backend, SIGNAL(currentAudioChannelChanged(int)),
-		this, SLOT(setCurrentAudioChannel(int)));
-	connect(backend, SIGNAL(subtitlesChanged(QStringList,int)),
-		this, SLOT(subtitlesChanged(QStringList,int)));
-	connect(backend, SIGNAL(currentSubtitleChanged(int)),
-		this, SLOT(setCurrentSubtitle(int)));
-	connect(backend, SIGNAL(dvdPlaybackChanged(bool)), this, \
                SLOT(dvdPlaybackChanged(bool)));
-	connect(backend, SIGNAL(titlesChanged(int,int)), this, \
                SLOT(titlesChanged(int,int)));
-	connect(backend, SIGNAL(currentTitleChanged(int)), this, \
                SLOT(setCurrentTitle(int)));
-	connect(backend, SIGNAL(chaptersChanged(int,int)), this, \
                SLOT(chaptersChanged(int,int)));
-	connect(backend, SIGNAL(currentChapterChanged(int)),
-		this, SLOT(setCurrentChapter(int)));
-	connect(backend, SIGNAL(anglesChanged(int,int)), this, \
                SLOT(anglesChanged(int,int)));
-	connect(backend, SIGNAL(currentAngleChanged(int)), this, \
                SLOT(setCurrentAngle(int)));
-	connect(backend, SIGNAL(videoSizeChanged()), this, SLOT(videoSizeChanged()));
+	connect(backend, SIGNAL(updatePlaybackStatus(MediaWidget::PlaybackStatus)),
+		this, SLOT(updatePlaybackStatus(MediaWidget::PlaybackStatus)));
+	connect(backend, SIGNAL(updateTotalTime(int)), this, SLOT(updateTotalTime(int)));
+	connect(backend, SIGNAL(updateCurrentTime(int)), this, \
SLOT(updateCurrentTime(int))); +	connect(backend, \
SIGNAL(updateMetadata(QMap<MediaWidget::MetadataType,QString>)), +		this, \
SLOT(updateMetadata(QMap<MediaWidget::MetadataType,QString>))); +	connect(backend, \
SIGNAL(updateSeekable(bool)), this, SLOT(updateSeekable(bool))); +	connect(backend, \
SIGNAL(updateAudioChannels(QStringList,int)), +		this, \
SLOT(updateAudioChannels(QStringList,int))); +	connect(backend, \
SIGNAL(updateSubtitles(QStringList,int)), +		this, \
SLOT(updateSubtitles(QStringList,int))); +	connect(backend, \
SIGNAL(updateTitles(int,int)), this, SLOT(updateTitles(int,int))); +	connect(backend, \
SIGNAL(updateChapters(int,int)), this, SLOT(updateChapters(int,int))); \
+	connect(backend, SIGNAL(updateAngles(int,int)), this, SLOT(updateAngles(int,int))); \
+	connect(backend, SIGNAL(updateDvdPlayback(bool)), this, \
SLOT(updateDvdPlayback(bool))); +	connect(backend, SIGNAL(updateVideoSize()), this, \
SLOT(updateVideoSize()));  layout->addWidget(backend);
 
 	osdWidget = new OsdWidget(this);
@@ -264,8 +109,6 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  menu->addAction(actionNext);
 	menu->addSeparator();
 
-	displayMode = NormalMode;
-
 	fullScreenAction = new KAction(KIcon("view-fullscreen"),
 		i18nc("'Playback' menu", "Full Screen Mode"), this);
 	fullScreenAction->setShortcut(Qt::Key_F);
@@ -279,14 +122,12 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  menu->addAction(collection->addAction("view_minimal_mode", \
minimalModeAction));  
 	audioChannelBox = new KComboBox(toolBar);
-	audioChannelsReady = false;
 	connect(audioChannelBox, SIGNAL(currentIndexChanged(int)),
 		this, SLOT(currentAudioChannelChanged(int)));
 	toolBar->addWidget(audioChannelBox);
 
 	subtitleBox = new KComboBox(toolBar);
 	textSubtitlesOff = i18nc("subtitle selection entry", "off");
-	subtitlesReady = false;
 	connect(subtitleBox, SIGNAL(currentIndexChanged(int)),
 		this, SLOT(currentSubtitleChanged(int)));
 	toolBar->addWidget(subtitleBox);
@@ -310,7 +151,6 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  unmutedIcon = KIcon("audio-volume-medium");
 	muteAction->setIcon(unmutedIcon);
 	muteAction->setShortcut(KShortcut(Qt::Key_M, Qt::Key_VolumeMute));
-	isMuted = false;
 	connect(muteAction, SIGNAL(triggered()), this, SLOT(mutedChanged()));
 	toolBar->addAction(collection->addAction("controls_mute_volume", muteAction));
 	audioMenu->addAction(muteAction);
@@ -379,14 +219,24 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  action->setData(2);
 	autoResizeMenu->addAction(collection->addAction("controls_autoresize_double", \
action));  
-	autoResizeFactor =
+	int autoResizeFactor =
 		KGlobal::config()->group("MediaObject").readEntry("AutoResizeFactor", 0);
 
-	if ((autoResizeFactor < 0) || (autoResizeFactor > 2)) {
-		autoResizeFactor = 0;
+	switch (autoResizeFactor) {
+	case 1:
+		automaticResize = OriginalSize;
+		autoResizeGroup->actions().at(1)->setChecked(true);
+		break;
+	case 2:
+		automaticResize = DoubleSize;
+		autoResizeGroup->actions().at(2)->setChecked(true);
+		break;
+	default:
+		automaticResize = ResizeOff;
+		autoResizeGroup->actions().at(0)->setChecked(true);
+		break;
 	}
 
-	autoResizeGroup->actions().at(autoResizeFactor)->setChecked(true);
 	videoMenu->addMenu(autoResizeMenu);
 
 	action = new KAction(i18n("Volume Slider"), this);
@@ -454,7 +304,7 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  seekSlider->setFocusPolicy(Qt::NoFocus);
 	seekSlider->setOrientation(Qt::Horizontal);
 	seekSlider->setToolTip(action->text());
-	connect(seekSlider, SIGNAL(valueChanged(int)), backend, SLOT(seek(int)));
+	connect(seekSlider, SIGNAL(valueChanged(int)), this, SLOT(seek(int)));
 	action->setDefaultWidget(seekSlider);
 	toolBar->addAction(collection->addAction("controls_position_slider", action));
 
@@ -485,7 +335,6 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  timeButton = new QPushButton(toolBar);
 	timeButton->setFocusPolicy(Qt::NoFocus);
 	timeButton->setToolTip(action->text());
-	showElapsedTime = true;
 	connect(timeButton, SIGNAL(clicked(bool)), this, SLOT(timeButtonClicked()));
 	action->setDefaultWidget(timeButton);
 	toolBar->addAction(collection->addAction("controls_time_button", action));
@@ -494,16 +343,16 @@ MediaWidget::MediaWidget(KMenu *menu_, KToolBar *toolBar, \
KActionCollection *col  timer->start(50000);
 	connect(timer, SIGNAL(timeout()), this, SLOT(checkScreenSaver()));
 
-	playbackChanged(false);
-	seekableChanged(false);
-	totalTimeChanged(0);
-	currentTimeChanged(0);
-	audioChannelsChanged(QStringList(), -1);
-	subtitlesChanged(QStringList(), -1);
-	dvdPlaybackChanged(false);
-	titlesChanged(0, -1);
-	chaptersChanged(0, -1);
-	anglesChanged(0, -1);
+	updatePlaybackStatus(Idle);
+	updateSeekable(false);
+	updateTotalTime(0);
+	updateCurrentTime(0);
+	updateAudioChannels(QStringList(), -1);
+	updateSubtitles(QStringList(), -1);
+	updateDvdPlayback(false);
+	updateTitles(0, -1);
+	updateChapters(0, -1);
+	updateAngles(0, -1);
 }
 
 MediaWidget::~MediaWidget()
@@ -511,6 +360,21 @@ MediaWidget::~MediaWidget()
 	KGlobal::config()->group("MediaObject").writeEntry("Volume", \
volumeSlider->value());  \
KGlobal::config()->group("MediaObject").writeEntry("Deinterlace",  \
deinterlaceAction->isChecked()); +
+	int autoResizeFactor = 0;
+
+	switch (automaticResize) {
+	case ResizeOff:
+		autoResizeFactor = 0;
+		break;
+	case OriginalSize:
+		autoResizeFactor = 1;
+		break;
+	case DoubleSize:
+		autoResizeFactor = 2;
+		break;
+	}
+
 	KGlobal::config()->group("MediaObject").writeEntry("AutoResizeFactor", \
autoResizeFactor);  }
 
@@ -573,27 +437,50 @@ void MediaWidget::setDisplayMode(DisplayMode displayMode_)
 	}
 }
 
-void MediaWidget::play(const KUrl &url, const KUrl &subtitleUrl)
+void MediaWidget::play(Source source_, const KUrl &url, const KUrl &subtitleUrl)
 {
-	currentSourceName = url.toLocalFile();
+	source = source_;
 
-	if (currentSourceName.isEmpty()) {
-		currentSourceName = url.fileName();
+	switch (source) {
+	case Playlist:
+		emit changeCaption(url.fileName());
+		break;
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+		emit changeCaption(QString());
+	case Dvb:
+	case DvbTimeShift:
+		break;
 	}
 
+	dvbAudioChannels.clear();
+	currentDvbAudioChannel = -1;
+	dvbSubtitles.clear();
 	externalSubtitles.clear();
-	currentExternalSubtitle = subtitleUrl;
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
-	backend->playUrl(url, subtitleUrl);
+	currentDvbSubtitle = -1;
+	currentExternalSubtitle = -1;
+
+	if (subtitleUrl.isValid()) {
+		externalSubtitles.append(subtitleUrl);
+		currentExternalSubtitle = 0;
+	}
+
+	backend->play(source, url, subtitleUrl);
+}
+
+void MediaWidget::play(const KUrl &url, const KUrl &subtitleUrl)
+{
+	play(Playlist, url, subtitleUrl);
 }
 
 void MediaWidget::playAudioCd(const QString &device)
 {
-	QString deviceName = device;
+	KUrl devicePath;
 
-	if (deviceName.isEmpty()) {
+	if (!device.isEmpty()) {
+		devicePath = QUrl::fromLocalFile(device);
+	} else {
 		QList<Solid::Device> devices =
 			Solid::Device::listFromQuery("OpticalDisc.availableContent & 'Audio'");
 
@@ -601,25 +488,21 @@ void MediaWidget::playAudioCd(const QString &device)
 			Solid::Block *block = devices.first().as<Solid::Block>();
 
 			if (block != NULL) {
-				deviceName = block->device();
+				devicePath = QUrl::fromLocalFile(block->device());
 			}
 		}
 	}
 
-	currentSourceName.clear();
-	externalSubtitles.clear();
-	currentExternalSubtitle.clear();
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
-	backend->playAudioCd(deviceName);
+	play(AudioCd, devicePath, KUrl());
 }
 
 void MediaWidget::playVideoCd(const QString &device)
 {
-	QString deviceName = device;
+	KUrl devicePath;
 
-	if (deviceName.isEmpty()) {
+	if (!device.isEmpty()) {
+		devicePath = QUrl::fromLocalFile(device);
+	} else {
 		QList<Solid::Device> devices = Solid::Device::listFromQuery(
 			"OpticalDisc.availableContent & 'VideoCd|SuperVideoCd'");
 
@@ -627,25 +510,21 @@ void MediaWidget::playVideoCd(const QString &device)
 			Solid::Block *block = devices.first().as<Solid::Block>();
 
 			if (block != NULL) {
-				deviceName = block->device();
+				devicePath = QUrl::fromLocalFile(block->device());
 			}
 		}
 	}
 
-	currentSourceName.clear();
-	externalSubtitles.clear();
-	currentExternalSubtitle.clear();
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
-	backend->playVideoCd(deviceName);
+	play(VideoCd, devicePath, KUrl());
 }
 
 void MediaWidget::playDvd(const QString &device)
 {
-	QString deviceName = device;
+	KUrl devicePath;
 
-	if (deviceName.isEmpty()) {
+	if (!device.isEmpty()) {
+		devicePath = QUrl::fromLocalFile(device);
+	} else {
 		QList<Solid::Device> devices =
 			Solid::Device::listFromQuery("OpticalDisc.availableContent & 'VideoDvd'");
 
@@ -653,123 +532,50 @@ void MediaWidget::playDvd(const QString &device)
 			Solid::Block *block = devices.first().as<Solid::Block>();
 
 			if (block != NULL) {
-				deviceName = block->device();
+				devicePath = QUrl::fromLocalFile(block->device());
 			}
 		}
 	}
 
-	currentSourceName.clear();
-	externalSubtitles.clear();
-	currentExternalSubtitle.clear();
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
-	backend->playDvd(deviceName);
-}
-
-void MediaWidget::updateExternalSubtitles(const QList<KUrl> &subtitles, int \
                currentSubtitle)
-{
-	if (!currentSourceName.isEmpty()) {
-		subtitlesReady = false;
-		externalSubtitles = subtitles;
-		int currentIndex;
-		KUrl externalSubtitle;
-
-		if (currentSubtitle < 0) {
-			currentIndex = subtitleBox->currentIndex();
-		} else {
-			currentIndex = currentSubtitle + subtitleBox->count();
-			externalSubtitle = subtitles.at(currentSubtitle);
-		}
-
-		if (currentExternalSubtitle != externalSubtitle) {
-			currentExternalSubtitle = externalSubtitle;
-			backend->setExternalSubtitle(currentExternalSubtitle);
-		}
-
-		foreach (const KUrl &subtitleUrl, subtitles) {
-			subtitleBox->addItem(subtitleUrl.fileName());
-		}
-
-		subtitleBox->setCurrentIndex(currentIndex);
-		subtitleBox->setEnabled(subtitleBox->count() > 1);
-		subtitlesReady = true;
-	}
-}
-
-OsdWidget *MediaWidget::getOsdWidget()
-{
-	return osdWidget;
+	play(Dvd, devicePath, KUrl());
 }
 
-void MediaWidget::playDvb(const QString &channelName)
+void MediaWidget::playDvb(Source source_, const KUrl &url, const QString \
&channelName)  {
-	delete dvbFeed;
-	dvbFeed = NULL;
-
-	seekableChanged(false);
-	totalTimeChanged(0);
-	currentTimeChanged(0);
-
-	dvbFeed = new DvbFeed(this);
-	dvbFeed->ignoreSourceChange = true;
 	emit changeCaption(channelName);
-	externalSubtitles.clear();
-	currentExternalSubtitle.clear();
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
-	backend->playUrl(dvbFeed->getUrl(), KUrl());
-	dvbFeed->ignoreSourceChange = false;
+	play(source_, url, KUrl());
 }
 
-void MediaWidget::writeDvbData(const QByteArray &data)
+void MediaWidget::updateExternalSubtitles(const QList<KUrl> &subtitles, int \
currentSubtitle)  {
-	dvbFeed->writeData(data);
+	externalSubtitles = subtitles;
+	currentExternalSubtitle = currentSubtitle;
+	updateSubtitleUi();
 }
 
-void MediaWidget::updateDvbAudioChannels(const QStringList &audioChannels, int \
currentAudioChannel) +OsdWidget *MediaWidget::getOsdWidget()
 {
-	dvbFeed->audioChannels = audioChannels;
-
-	if (!audioChannels.isEmpty()) {
-		audioChannelsReady = false;
-		audioChannelBox->clear();
-		audioChannelBox->addItems(audioChannels);
-		audioChannelBox->setCurrentIndex(currentAudioChannel);
-		audioChannelBox->setEnabled(audioChannelBox->count() > 1);
-		audioChannelsReady = true;
-	} else {
-		audioChannelsChanged(backend->getAudioChannels(),
-			backend->getCurrentAudioChannel());
-	}
+	return osdWidget;
 }
 
-void MediaWidget::updateDvbSubtitles(const QStringList &subtitles, int \
currentSubtitle) +void MediaWidget::updateDvbAudioChannels(const QStringList \
&dvbAudioChannels_, +	int currentDvbAudioChannel_)
 {
-	dvbFeed->subtitles = subtitles;
-
-	if (!subtitles.isEmpty()) {
-		subtitlesReady = false;
-		subtitleBox->clear();
-		subtitleBox->addItem(textSubtitlesOff);
-		subtitleBox->addItems(subtitles);
-		subtitleBox->setCurrentIndex(currentSubtitle + 1);
-		subtitleBox->setEnabled(subtitleBox->count() > 1);
-		subtitlesReady = true;
-	} else {
-		subtitlesChanged(backend->getSubtitles(), backend->getCurrentSubtitle());
-	}
+	dvbAudioChannels = dvbAudioChannels_;
+	currentDvbAudioChannel = currentDvbAudioChannel_;
+	updateAudioChannelUi();
 }
 
-bool MediaWidget::isPlaying() const
+void MediaWidget::updateDvbSubtitles(const QStringList &dvbSubtitles_, int \
currentDvbSubtitle_)  {
-	return backend->isPlaying();
+	dvbSubtitles = dvbSubtitles_;
+	currentDvbSubtitle = currentDvbSubtitle_;
+	updateSubtitleUi();
 }
 
-bool MediaWidget::isPaused() const
+MediaWidget::PlaybackStatus MediaWidget::getPlaybackStatus() const
 {
-	return actionPlayPause->isChecked();
+	return backendPlaybackStatus;
 }
 
 int MediaWidget::getVolume() const
@@ -779,15 +585,21 @@ int MediaWidget::getVolume() const
 
 int MediaWidget::getPosition() const
 {
-	return backend->getCurrentTime();
+	return backendCurrentTime;
 }
 
 void MediaWidget::play()
 {
-	// FIXME not the best behaviour
-
-	if (dvbFeed == NULL) {
+	switch (source) {
+	case Playlist:
 		emit playlistPlay();
+		break;
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+	case Dvb:
+	case DvbTimeShift:
+		break;
 	}
 }
 
@@ -814,34 +626,55 @@ void MediaWidget::toggleMuted()
 
 void MediaWidget::previous()
 {
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
+	switch (source) {
+	case Playlist:
+		if (!backend->jumpToPreviousChapter()) {
+			emit playlistPrevious();
+		}
 
-	if (dvbFeed != NULL) {
-		emit previousDvbChannel();
-	} else if (!backend->playPreviousTitle()) {
-		emit playlistPrevious();
+		break;
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+		backend->jumpToPreviousChapter();
+		break;
+	case Dvb:
+	case DvbTimeShift:
+		emit dvbPreviousChannel();
+		break;
 	}
 }
 
 void MediaWidget::next()
 {
-	actionPlayPause->setText(textPause);
-	actionPlayPause->setIcon(iconPause);
-	actionPlayPause->setChecked(false);
+	switch (source) {
+	case Playlist:
+		if (!backend->jumpToNextChapter()) {
+			emit playlistNext();
+		}
 
-	if (dvbFeed != NULL) {
-		emit nextDvbChannel();
-	} else if (!backend->playNextTitle()) {
-		emit playlistNext();
+		break;
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+		backend->jumpToNextChapter();
+		break;
+	case Dvb:
+	case DvbTimeShift:
+		emit dvbNextChannel();
+		break;
 	}
 }
 
 void MediaWidget::stop()
 {
-	if (backend->isPlaying()) {
+	switch (backendPlaybackStatus) {
+	case Idle:
+		break;
+	case Playing:
+	case Paused:
 		osdWidget->showText(i18nc("osd", "Stopped"), 1500);
+		break;
 	}
 
 	backend->stop();
@@ -859,47 +692,79 @@ void MediaWidget::decreaseVolume()
 	volumeSlider->setValue(volumeSlider->value() - 5);
 }
 
-void MediaWidget::sourceChanged()
+void MediaWidget::playbackFinished()
 {
-	if ((dvbFeed != NULL) && !dvbFeed->ignoreSourceChange) {
-		stopDvbPlayback();
-	}
-
-	setMetadata(QMap<MetadataType, QString>());
-
-	if (autoResizeFactor > 0) {
-		emit resizeToVideo(autoResizeFactor);
+	switch (source) {
+	case Playlist:
+		emit playlistNext();
+		break;
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+		break;
+	case Dvb:
+	case DvbTimeShift:
+		emit dvbStartTimeShift();
+		break;
 	}
 }
 
-void MediaWidget::playbackFinished()
+void MediaWidget::updatePlaybackStatus(PlaybackStatus playbackStatus)
 {
-	currentSourceName.clear();
+	backendPlaybackStatus = playbackStatus;
+	bool playing = true;
 
-	if (dvbFeed != NULL) {
-		dvbFeed->ignoreSourceChange = true;
-		emit startDvbTimeShift();
-		dvbFeed->ignoreSourceChange = false;
-	} else {
+	switch (playbackStatus) {
+	case Idle:
 		emit changeCaption(QString());
-		emit playlistNext();
-	}
-}
+		actionPlayPause->setIcon(iconPlay);
+		actionPlayPause->setText(textPlay);
+		playing = false;
+		dvbAudioChannels.clear();
+		currentDvbAudioChannel = -1;
+		dvbSubtitles.clear();
+		externalSubtitles.clear();
+		currentDvbSubtitle = -1;
+		currentExternalSubtitle = -1;
+		break;
+	case Playing:
+		actionPlayPause->setIcon(iconPause);
+		actionPlayPause->setText(textPause);
+		osdWidget->showText(i18nc("osd", "Playing"), 1500);
+
+		switch (source) {
+		case Playlist:
+		case AudioCd:
+		case VideoCd:
+		case Dvd:
+		case DvbTimeShift:
+			break;
+		case Dvb:
+			emit dvbStartTimeShift();
+			break;
+		}
 
-void MediaWidget::playbackStopped()
-{
-	currentSourceName.clear();
-	emit changeCaption(QString());
+		break;
+	case Paused:
+		actionPlayPause->setIcon(iconPlay);
+		actionPlayPause->setText(textPlay);
+		osdWidget->showText(i18nc("osd", "Paused"), 1500);
+
+		switch (source) {
+		case Playlist:
+		case AudioCd:
+		case VideoCd:
+		case Dvd:
+		case DvbTimeShift:
+			break;
+		case Dvb:
+			emit dvbPrepareTimeShift();
+			break;
+		}
 
-	if (dvbFeed != NULL) {
-		stopDvbPlayback();
+		break;
 	}
-}
 
-void MediaWidget::playbackChanged(bool playing)
-{
-	actionPlayPause->setText(playing ? textPause : textPlay);
-	actionPlayPause->setIcon(playing ? iconPause : iconPlay);
 	actionPlayPause->setCheckable(playing);
 	actionPrevious->setEnabled(playing);
 	actionStop->setEnabled(playing);
@@ -907,28 +772,52 @@ void MediaWidget::playbackChanged(bool playing)
 	timeButton->setEnabled(playing);
 }
 
-void MediaWidget::totalTimeChanged(int totalTime)
+void MediaWidget::updateTotalTime(int totalTime)
 {
-	if ((dvbFeed == NULL) || dvbFeed->timeShiftActive) {
-		seekSlider->setRange(0, totalTime);
+	if (totalTime < 0) {
+		totalTime = 0;
 	}
 
-	if (!currentSourceName.isEmpty() && (dvbFeed == NULL)) {
-		emit playlistTrackLengthChanged(totalTime);
+	backendTotalTime = totalTime;
+
+	switch (source) {
+	case Playlist:
+		emit playlistTrackLengthChanged(backendTotalTime);
+		break;
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+	case Dvb:
+	case DvbTimeShift:
+		break;
 	}
+
+	updateCurrentTotalTimeUi();
 }
 
-void MediaWidget::currentTimeChanged(int currentTime)
+void MediaWidget::updateCurrentTime(int currentTime)
 {
-	if ((dvbFeed == NULL) || dvbFeed->timeShiftActive) {
-		seekSlider->setValue(currentTime);
-		updateTimeButton();
+	if (currentTime < 0) {
+		currentTime = 0;
+	}
+
+	if (currentTime > backendTotalTime) {
+		currentTime = backendTotalTime;
 	}
+
+	backendCurrentTime = currentTime;
+	updateCurrentTotalTimeUi();
 }
 
-void MediaWidget::setMetadata(const QMap<MetadataType, QString> &metadata)
+void MediaWidget::updateMetadata(const QMap<MetadataType, QString> &metadata)
 {
-	if (dvbFeed == NULL) {
+	switch (source) {
+	case Playlist:
+		emit playlistTrackMetadataChanged(metadata);
+		// fall through
+	case AudioCd:
+	case VideoCd:
+	case Dvd: {
 		QString caption = metadata.value(Title);
 		QString artist = metadata.value(Artist);
 
@@ -942,93 +831,59 @@ void MediaWidget::setMetadata(const QMap<MetadataType, QString> \
&metadata)  caption += ')';
 		}
 
-		if (caption.isEmpty()) {
-			caption = currentSourceName;
-		}
-
 		if (!caption.isEmpty()) {
 			osdWidget->showText(caption, 2500);
+			emit changeCaption(caption);
 		}
 
-		emit changeCaption(caption);
-
-		if (!currentSourceName.isEmpty()) {
-			emit playlistTrackMetadataChanged(metadata);
-		}
-	}
-}
-
-void MediaWidget::seekableChanged(bool seekable)
-{
-	if ((dvbFeed == NULL) || dvbFeed->timeShiftActive) {
-		seekSlider->setEnabled(seekable);
-		navigationMenu->setEnabled(seekable);
-		jumpToPositionAction->setEnabled(seekable);
+		break;
+	    }
+	case Dvb:
+	case DvbTimeShift:
+		break;
 	}
 }
 
-void MediaWidget::audioChannelsChanged(const QStringList &audioChannels, int \
currentAudioChannel) +void MediaWidget::updateSeekable(bool seekable)
 {
-	if ((dvbFeed == NULL) || dvbFeed->audioChannels.isEmpty()) {
-		audioChannelsReady = false;
-		audioChannelBox->clear();
-		audioChannelBox->addItems(audioChannels);
-		audioChannelBox->setCurrentIndex(currentAudioChannel);
-		audioChannelBox->setEnabled(audioChannelBox->count() > 1);
-		audioChannelsReady = true;
-	}
+	backendSeekable = seekable;
+	updateSeekableUi();
 }
 
-void MediaWidget::setCurrentAudioChannel(int currentAudioChannel)
+void MediaWidget::updateAudioChannels(const QStringList &audioChannels, int \
currentAudioChannel)  {
-	if ((dvbFeed == NULL) || dvbFeed->audioChannels.isEmpty()) {
-		audioChannelBox->setCurrentIndex(currentAudioChannel);
-	}
+	backendAudioChannels = audioChannels;
+	currentBackendAudioChannel = currentAudioChannel;
+	updateAudioChannelUi();
 }
 
-void MediaWidget::subtitlesChanged(const QStringList &subtitles, int \
currentSubtitle) +void MediaWidget::updateSubtitles(const QStringList &subtitles, int \
currentSubtitle)  {
-	if ((dvbFeed == NULL) || dvbFeed->subtitles.isEmpty()) {
-		subtitlesReady = false;
-		subtitleBox->clear();
-		subtitleBox->addItem(textSubtitlesOff);
-		subtitleBox->addItems(subtitles);
-		int currentIndex;
+	backendSubtitles = subtitles;
+	currentBackendSubtitle = currentSubtitle;
 
-		if (currentExternalSubtitle.isValid()) {
-			currentIndex = (externalSubtitles.indexOf(currentExternalSubtitle) +
-				subtitleBox->count());
-		} else {
-			currentIndex = (currentSubtitle + 1);
-		}
+	if (!dvbSubtitles.isEmpty()) {
+		// subtitles are overriden --> automatically choose appropriate subtitle
+		int selectedSubtitle = -1;
 
-		foreach (const KUrl &subtitleUrl, externalSubtitles) {
-			subtitleBox->addItem(subtitleUrl.fileName());
+		if (currentDvbSubtitle >= 0) {
+			selectedSubtitle = (backendSubtitles.size() - 1);
 		}
 
-		subtitleBox->setCurrentIndex(currentIndex);
-		subtitleBox->setEnabled(subtitleBox->count() > 1);
-		subtitlesReady = true;
-	} else {
-		if (!subtitles.isEmpty()) {
-			backend->setCurrentSubtitle(0);
+		if (currentBackendSubtitle != selectedSubtitle) {
+			backend->setCurrentSubtitle(selectedSubtitle);
 		}
 	}
-}
 
-void MediaWidget::setCurrentSubtitle(int currentSubtitle)
-{
-	if ((dvbFeed == NULL) || dvbFeed->subtitles.isEmpty()) {
-		subtitleBox->setCurrentIndex(currentSubtitle + 1);
-	}
+	updateSubtitleUi();
 }
 
-void MediaWidget::dvdPlaybackChanged(bool playingDvd)
+void MediaWidget::updateDvdPlayback(bool playingDvd)
 {
 	menuAction->setEnabled(playingDvd);
 }
 
-void MediaWidget::titlesChanged(int titleCount, int currentTitle)
+void MediaWidget::updateTitles(int titleCount, int currentTitle)
 {
 	if (titleCount > 1) {
 		QList<QAction *> actions = titleGroup->actions();
@@ -1050,23 +905,19 @@ void MediaWidget::titlesChanged(int titleCount, int \
currentTitle)  actions.at(i)->setVisible(i < titleCount);
 		}
 
-		setCurrentTitle(currentTitle);
+		if ((currentTitle >= 1) && (currentTitle <= titleGroup->actions().count())) {
+			titleGroup->actions().at(currentTitle - 1)->setChecked(true);
+		} else if (titleGroup->checkedAction() != NULL) {
+			titleGroup->checkedAction()->setChecked(false);
+		}
+
 		titleMenu->setEnabled(true);
 	} else {
 		titleMenu->setEnabled(false);
 	}
 }
 
-void MediaWidget::setCurrentTitle(int currentTitle)
-{
-	if ((currentTitle >= 1) && (currentTitle <= titleGroup->actions().count())) {
-		titleGroup->actions().at(currentTitle - 1)->setChecked(true);
-	} else if (titleGroup->checkedAction() != NULL) {
-		titleGroup->checkedAction()->setChecked(false);
-	}
-}
-
-void MediaWidget::chaptersChanged(int chapterCount, int currentChapter)
+void MediaWidget::updateChapters(int chapterCount, int currentChapter)
 {
 	if (chapterCount > 1) {
 		QList<QAction *> actions = chapterGroup->actions();
@@ -1088,23 +939,19 @@ void MediaWidget::chaptersChanged(int chapterCount, int \
currentChapter)  actions.at(i)->setVisible(i < chapterCount);
 		}
 
-		setCurrentChapter(currentChapter);
+		if ((currentChapter >= 1) && (currentChapter <= chapterGroup->actions().count())) \
{ +			chapterGroup->actions().at(currentChapter - 1)->setChecked(true);
+		} else if (chapterGroup->checkedAction() != NULL) {
+			chapterGroup->checkedAction()->setChecked(false);
+		}
+
 		chapterMenu->setEnabled(true);
 	} else {
 		chapterMenu->setEnabled(false);
 	}
 }
 
-void MediaWidget::setCurrentChapter(int currentChapter)
-{
-	if ((currentChapter >= 1) && (currentChapter <= chapterGroup->actions().count())) {
-		chapterGroup->actions().at(currentChapter - 1)->setChecked(true);
-	} else if (chapterGroup->checkedAction() != NULL) {
-		chapterGroup->checkedAction()->setChecked(false);
-	}
-}
-
-void MediaWidget::anglesChanged(int angleCount, int currentAngle)
+void MediaWidget::updateAngles(int angleCount, int currentAngle)
 {
 	if (angleCount > 1) {
 		QList<QAction *> actions = angleGroup->actions();
@@ -1126,32 +973,37 @@ void MediaWidget::anglesChanged(int angleCount, int \
currentAngle)  actions.at(i)->setVisible(i < angleCount);
 		}
 
-		setCurrentAngle(currentAngle);
+		if ((currentAngle >= 1) && (currentAngle <= angleGroup->actions().count())) {
+			angleGroup->actions().at(currentAngle - 1)->setChecked(true);
+		} else if (angleGroup->checkedAction() != NULL) {
+			angleGroup->checkedAction()->setChecked(false);
+		}
+
 		angleMenu->setEnabled(true);
 	} else {
 		angleMenu->setEnabled(false);
 	}
 }
 
-void MediaWidget::setCurrentAngle(int currentAngle)
-{
-	if ((currentAngle >= 1) && (currentAngle <= angleGroup->actions().count())) {
-		angleGroup->actions().at(currentAngle - 1)->setChecked(true);
-	} else if (angleGroup->checkedAction() != NULL) {
-		angleGroup->checkedAction()->setChecked(false);
-	}
-}
-
-void MediaWidget::videoSizeChanged()
+void MediaWidget::updateVideoSize()
 {
-	if (autoResizeFactor > 0) {
-		emit resizeToVideo(autoResizeFactor);
+	if (automaticResize != ResizeOff) {
+		emit resizeToVideo(automaticResize);
 	}
 }
 
 void MediaWidget::checkScreenSaver()
 {
-	bool suspendScreenSaver = (backend->isPlaying() && !isPaused() && isVisible());
+	bool suspendScreenSaver = false;
+
+	switch (backendPlaybackStatus) {
+	case Idle:
+	case Paused:
+		break;
+	case Playing:
+		suspendScreenSaver = isVisible();
+		break;
+	}
 
 	if (suspendScreenSaver) {
 		// KDE - Inhibit doesn't inhibit "lock screen after inactivity"
@@ -1173,10 +1025,10 @@ void MediaWidget::checkScreenSaver()
 
 void MediaWidget::mutedChanged()
 {
-	isMuted = !isMuted;
-	backend->setMuted(isMuted);
+	muted = !muted;
+	backend->setMuted(muted);
 
-	if (isMuted) {
+	if (muted) {
 		muteAction->setIcon(mutedIcon);
 		osdWidget->showText(i18nc("osd", "Mute On"), 1500);
 	} else {
@@ -1209,6 +1061,15 @@ void MediaWidget::toggleMinimalMode()
 	}
 }
 
+void MediaWidget::seek(int position)
+{
+	if (blockBackendUpdates) {
+		return;
+	}
+
+	backend->seek(position);
+}
+
 void MediaWidget::deinterlacingChanged(bool deinterlacing)
 {
 	backend->setDeinterlacing(deinterlacing);
@@ -1239,17 +1100,23 @@ void MediaWidget::autoResizeTriggered(QAction *action)
 		autoResizeAction->setChecked(autoResizeAction == action);
 	}
 
-	bool ok;
-	unsigned int autoResizeFactor_ = action->data().toInt(&ok);
-
-	if (ok && (autoResizeFactor_ <= 2)) {
-		autoResizeFactor = autoResizeFactor_;
-
-		if (autoResizeFactor > 0) {
-			emit resizeToVideo(autoResizeFactor);
+	bool ok = false;
+	int autoResizeFactor = action->data().toInt(&ok);
+
+	if (ok) {
+		switch (autoResizeFactor) {
+		case 0:
+			automaticResize = ResizeOff;
+			return;
+		case 1:
+			automaticResize = OriginalSize;
+			emit(automaticResize);
+			return;
+		case 2:
+			automaticResize = DoubleSize;
+			emit(automaticResize);
+			return;
 		}
-
-		return;
 	}
 
 	Log("MediaWidget::autoResizeTriggered: internal error");
@@ -1257,78 +1124,57 @@ void MediaWidget::autoResizeTriggered(QAction *action)
 
 void MediaWidget::pausedChanged(bool paused)
 {
-	if (backend->isPlaying()) {
-		if (paused) {
-			actionPlayPause->setIcon(iconPlay);
-			actionPlayPause->setText(textPlay);
-			osdWidget->showText(i18nc("osd", "Paused"), 1500);
-			backend->setPaused(true);
-
-			if ((dvbFeed != NULL) && !dvbFeed->timeShiftPrepared) {
-				dvbFeed->timeShiftPrepared = true;
-				dvbFeed->endOfData();
-				emit prepareDvbTimeShift();
-			}
-		} else {
-			actionPlayPause->setIcon(iconPause);
-			actionPlayPause->setText(textPause);
-			osdWidget->showText(i18nc("osd", "Playing"), 1500);
-
-			if ((dvbFeed != NULL) && !dvbFeed->timeShiftActive &&
-			    dvbFeed->timeShiftPrepared) {
-				dvbFeed->timeShiftActive = true;
-				dvbFeed->ignoreSourceChange = true;
-				emit startDvbTimeShift();
-				dvbFeed->ignoreSourceChange = false;
-			} else {
-				backend->setPaused(false);
-			}
-		}
-	} else {
+	switch (backendPlaybackStatus) {
+	case Idle:
 		emit playlistPlay();
+		break;
+	case Playing:
+	case Paused:
+		backend->setPaused(paused);
+		break;
 	}
 }
 
 void MediaWidget::timeButtonClicked()
 {
 	showElapsedTime = !showElapsedTime;
-	updateTimeButton();
+	updateCurrentTotalTimeUi();
 }
 
 void MediaWidget::longSkipBackward()
 {
 	int longSkipDuration = Configuration::instance()->getLongSkipDuration();
-	int time = backend->getCurrentTime() - 1000 * longSkipDuration;
+	int currentTime = (backendCurrentTime - 1000 * longSkipDuration);
 
-	if (time < 0) {
-		time = 0;
+	if (currentTime < 0) {
+		currentTime = 0;
 	}
 
-	backend->seek(time);
+	backend->seek(currentTime);
 }
 
 void MediaWidget::shortSkipBackward()
 {
 	int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
-	int time = backend->getCurrentTime() - 1000 * shortSkipDuration;
+	int currentTime = (backendCurrentTime - 1000 * shortSkipDuration);
 
-	if (time < 0) {
-		time = 0;
+	if (currentTime < 0) {
+		currentTime = 0;
 	}
 
-	backend->seek(time);
+	backend->seek(currentTime);
 }
 
 void MediaWidget::shortSkipForward()
 {
 	int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
-	backend->seek(backend->getCurrentTime() + 1000 * shortSkipDuration);
+	backend->seek(backendCurrentTime + 1000 * shortSkipDuration);
 }
 
 void MediaWidget::longSkipForward()
 {
 	int longSkipDuration = Configuration::instance()->getLongSkipDuration();
-	backend->seek(backend->getCurrentTime() + 1000 * longSkipDuration);
+	backend->seek(backendCurrentTime + 1000 * longSkipDuration);
 }
 
 void MediaWidget::jumpToPosition()
@@ -1341,36 +1187,47 @@ void MediaWidget::jumpToPosition()
 
 void MediaWidget::currentAudioChannelChanged(int currentAudioChannel)
 {
-	if (audioChannelsReady) {
-		if ((dvbFeed == NULL) || dvbFeed->audioChannels.isEmpty()) {
-			backend->setCurrentAudioChannel(currentAudioChannel);
-		} else {
-			emit changeDvbAudioChannel(currentAudioChannel);
-		}
+	if (blockBackendUpdates) {
+		return;
+	}
+
+	if (dvbAudioChannels.isEmpty()) {
+		backend->setCurrentAudioChannel(currentAudioChannel);
+	} else {
+		emit dvbSetCurrentAudioChannel(currentAudioChannel);
 	}
 }
 
 void MediaWidget::currentSubtitleChanged(int currentSubtitle)
 {
-	if (subtitlesReady) {
-		if ((dvbFeed == NULL) || dvbFeed->subtitles.isEmpty()) {
+	if (blockBackendUpdates) {
+		return;
+	}
+
+	--currentSubtitle;
+
+	if (dvbSubtitles.isEmpty()) {
+		int oldExternalSubtitle = currentExternalSubtitle;
+
+		if (currentSubtitle < backendSubtitles.size()) {
+			currentExternalSubtitle = -1;
+			backend->setCurrentSubtitle(currentSubtitle);
+		} else {
+			currentExternalSubtitle = (currentSubtitle - backendSubtitles.size());
+		}
+
+		if (currentExternalSubtitle != oldExternalSubtitle) {
 			KUrl externalSubtitle;
 
-			if (currentSubtitle < (subtitleBox->count() - externalSubtitles.count())) {
-				backend->setCurrentSubtitle(currentSubtitle - 1);
-			} else {
-				backend->setCurrentSubtitle(-1);
-				externalSubtitle = externalSubtitles.at(currentSubtitle -
-					(subtitleBox->count() - externalSubtitles.count()));
+			if ((currentExternalSubtitle >= 0) &&
+			    (currentExternalSubtitle < externalSubtitles.size())) {
+				externalSubtitle = externalSubtitles.at(currentExternalSubtitle);
 			}
 
-			if (currentExternalSubtitle != externalSubtitle) {
-				currentExternalSubtitle = externalSubtitle;
-				backend->setExternalSubtitle(currentExternalSubtitle);
-			}
-		} else {
-			emit changeDvbSubtitle(currentSubtitle - 1);
+			backend->setExternalSubtitle(externalSubtitle);
 		}
+	} else {
+		emit dvbSetCurrentSubtitle(currentSubtitle);
 	}
 }
 
@@ -1410,26 +1267,105 @@ void MediaWidget::longSkipDurationChanged(int \
longSkipDuration)  longSkipDuration));
 }
 
-void MediaWidget::updateTimeButton()
+void MediaWidget::updateAudioChannelUi()
 {
+	blockBackendUpdates = true;
+	audioChannelBox->clear();
+
+	if (dvbAudioChannels.isEmpty()) {
+		audioChannelBox->addItems(backendAudioChannels);
+		audioChannelBox->setCurrentIndex(currentBackendAudioChannel);
+	} else {
+		audioChannelBox->addItems(dvbAudioChannels);
+		audioChannelBox->setCurrentIndex(currentDvbAudioChannel);
+	}
+
+	audioChannelBox->setEnabled(audioChannelBox->count() > 1);
+	blockBackendUpdates = false;
+}
+
+void MediaWidget::updateSubtitleUi()
+{
+	blockBackendUpdates = true;
+	subtitleBox->clear();
+	subtitleBox->addItem(textSubtitlesOff);
+
+	if (dvbSubtitles.isEmpty()) {
+		subtitleBox->addItems(backendSubtitles);
+
+		foreach (const KUrl &subtitleUrl, externalSubtitles) {
+			subtitleBox->addItem(subtitleUrl.fileName());
+		}
+
+		int currentIndex;
+
+		if (currentExternalSubtitle < 0) {
+			currentIndex = (currentBackendSubtitle + 1);
+		} else {
+			currentIndex = (currentExternalSubtitle + backendSubtitles.size() + 1);
+		}
+
+		subtitleBox->setCurrentIndex(currentIndex);
+	} else {
+		subtitleBox->addItems(dvbSubtitles);
+		subtitleBox->setCurrentIndex(currentDvbSubtitle + 1);
+	}
+
+	subtitleBox->setEnabled(subtitleBox->count() > 1);
+	blockBackendUpdates = false;
+}
+
+void MediaWidget::updateCurrentTotalTimeUi()
+{
+	int currentTime = backendCurrentTime;
+	int totalTime = backendTotalTime;
+
+	switch (source) {
+	case Playlist:
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+	case DvbTimeShift:
+		break;
+	case Dvb:
+		currentTime = 0;
+		totalTime = 0;
+		break;
+	}
+
+	blockBackendUpdates = true;
+	seekSlider->setRange(0, totalTime);
+	seekSlider->setValue(currentTime);
+
 	if (showElapsedTime) {
-		timeButton->setText(' ' + QTime(0, 0).addMSecs(seekSlider->value()).toString());
+		timeButton->setText(' ' + QTime(0, 0).addMSecs(currentTime).toString());
 	} else {
-		int remainingTime = seekSlider->maximum() - seekSlider->value();
+		int remainingTime = (totalTime - currentTime);
 		timeButton->setText('-' + QTime(0, 0).addMSecs(remainingTime).toString());
 	}
+
+	blockBackendUpdates = false;
 }
 
-void MediaWidget::stopDvbPlayback()
+void MediaWidget::updateSeekableUi()
 {
-	delete dvbFeed;
-	dvbFeed = NULL;
-	totalTimeChanged(backend->getTotalTime());
-	currentTimeChanged(backend->getCurrentTime());
-	seekableChanged(backend->isSeekable());
-	audioChannelsChanged(QStringList(), -1);
-	subtitlesChanged(QStringList(), -1);
-	emit dvbStopped();
+	bool seekable = backendSeekable;
+
+	switch (source) {
+	case Playlist:
+	case AudioCd:
+	case VideoCd:
+	case Dvd:
+	case DvbTimeShift:
+		break;
+	case Dvb:
+		seekable = false;
+		break;
+	}
+
+	seekSlider->setEnabled(seekable);
+	navigationMenu->setEnabled(seekable);
+	jumpToPositionAction->setEnabled(seekable);
 }
 
 void MediaWidget::contextMenuEvent(QContextMenuEvent *event)
@@ -1480,15 +1416,50 @@ void MediaWidget::resizeEvent(QResizeEvent *event)
 void MediaWidget::wheelEvent(QWheelEvent *event)
 {
 	int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
+	int currentTime = (backendCurrentTime - ((25 * shortSkipDuration * event->delta()) \
/ 3));  
-	if (backend->isSeekable()) {
-		qint64 time = (backend->getCurrentTime() -
-			(25 * shortSkipDuration * event->delta()) / 3);
+	if (currentTime < 0) {
+		currentTime = 0;
+	}
 
-		if (time < 0) {
-			time = 0;
-		}
+	backend->seek(currentTime);
+}
 
-		backend->seek(time);
-	}
+JumpToPositionDialog::JumpToPositionDialog(MediaWidget *mediaWidget_) : \
KDialog(mediaWidget_), +	mediaWidget(mediaWidget_)
+{
+	setCaption(i18nc("@title:window", "Jump to Position"));
+
+	QWidget *widget = new QWidget(this);
+	QBoxLayout *layout = new QVBoxLayout(widget);
+
+	layout->addWidget(new QLabel(i18n("Enter a position:")));
+
+	timeEdit = new QTimeEdit(this);
+	timeEdit->setDisplayFormat("hh:mm:ss");
+	timeEdit->setTime(QTime().addMSecs(mediaWidget->getPosition()));
+	layout->addWidget(timeEdit);
+
+	timeEdit->setFocus();
+
+	setMainWidget(widget);
+}
+
+JumpToPositionDialog::~JumpToPositionDialog()
+{
+}
+
+void JumpToPositionDialog::accept()
+{
+	mediaWidget->setPosition(QTime().msecsTo(timeEdit->time()));
+	KDialog::accept();
+}
+
+void SeekSlider::mousePressEvent(QMouseEvent *event)
+{
+	int buttons = style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons);
+	Qt::MouseButton button = static_cast<Qt::MouseButton>(buttons & (~(buttons - 1)));
+	QMouseEvent modifiedEvent(event->type(), event->pos(), event->globalPos(), button,
+		event->buttons() ^ event->button() ^ button, event->modifiers());
+	QSlider::mousePressEvent(&modifiedEvent);
 }
diff --git a/src/mediawidget.h b/src/mediawidget.h
index 31bc030..a0e8661 100644
--- a/src/mediawidget.h
+++ b/src/mediawidget.h
@@ -33,10 +33,9 @@ class KActionCollection;
 class KComboBox;
 class KMenu;
 class KToolBar;
-class DvbFeed;
+class AbstractMediaWidget;
 class OsdWidget;
 class SeekSlider;
-class XineMediaWidget;
 
 class MediaWidget : public QWidget
 {
@@ -48,26 +47,53 @@ public:
 
 	static QString extensionFilter(); // usable for KFileDialog::setFilter()
 
-	enum AspectRatio {
+	enum AspectRatio
+	{
 		AspectRatioAuto,
 		AspectRatio4_3,
 		AspectRatio16_9,
 		AspectRatioWidget
 	};
 
-	enum DisplayMode {
+	enum DisplayMode
+	{
 		NormalMode,
 		FullScreenMode,
 		MinimalMode
 	};
 
-	enum MetadataType {
+	enum MetadataType
+	{
 		Title,
 		Artist,
 		Album,
 		TrackNumber
 	};
 
+	enum PlaybackStatus
+	{
+		Idle,
+		Playing,
+		Paused
+	};
+
+	enum ResizeFactor
+	{
+		ResizeOff,
+		OriginalSize,
+		DoubleSize
+	};
+
+	enum Source
+	{
+		Playlist,
+		AudioCd,
+		VideoCd,
+		Dvd,
+		Dvb,
+		DvbTimeShift
+	};
+
 	DisplayMode getDisplayMode() const;
 	void setDisplayMode(DisplayMode displayMode_);
 
@@ -75,7 +101,9 @@ public:
 	 * loads the media and starts playback
 	 */
 
+	void play(Source source_, const KUrl &url, const KUrl &subtitleUrl);
 	void play(const KUrl &url, const KUrl &subtitleUrl = KUrl());
+	void playDvb(Source source_, const KUrl &url, const QString &channelName);
 	void playAudioCd(const QString &device);
 	void playVideoCd(const QString &device);
 	void playDvd(const QString &device);
@@ -83,15 +111,12 @@ public:
 
 	OsdWidget *getOsdWidget();
 
-	void playDvb(const QString &channelName); // starts dvb mode
-	void writeDvbData(const QByteArray &data);
-
-	// empty list = use audio channels / subtitles provided by phonon
-	void updateDvbAudioChannels(const QStringList &audioChannels, int \
                currentAudioChannel);
-	void updateDvbSubtitles(const QStringList &subtitles, int currentSubtitle);
+	// empty list = use audio channels / subtitles provided by the backend
+	void updateDvbAudioChannels(const QStringList &dvbAudioChannels_,
+		int currentDvbAudioChannel_);
+	void updateDvbSubtitles(const QStringList &dvbSubtitles_, int currentDvbSubtitle_);
 
-	bool isPlaying() const;
-	bool isPaused() const;
+	PlaybackStatus getPlaybackStatus() const;
 	int getPosition() const; // milliseconds
 	int getVolume() const; // 0 - 100
 
@@ -117,7 +142,7 @@ public slots:
 signals:
 	void displayModeChanged();
 	void changeCaption(const QString &caption);
-	void resizeToVideo(int factor);
+	void resizeToVideo(MediaWidget::ResizeFactor resizeFactor);
 
 	void playlistPrevious();
 	void playlistPlay();
@@ -127,40 +152,35 @@ signals:
 	void playlistTrackMetadataChanged(
 		const QMap<MediaWidget::MetadataType, QString> &metadata);
 
-	void previousDvbChannel();
-	void nextDvbChannel();
-	void prepareDvbTimeShift();
-	void startDvbTimeShift();
-	void changeDvbAudioChannel(int index);
-	void changeDvbSubtitle(int index);
-	void dvbStopped();
 	void osdKeyPressed(int key);
+	void dvbStopped();
+	void dvbPrepareTimeShift();
+	void dvbStartTimeShift();
+	void dvbSetCurrentAudioChannel(int index);
+	void dvbSetCurrentSubtitle(int index);
+	void dvbPreviousChannel();
+	void dvbNextChannel();
 
 private slots:
-	void sourceChanged();
 	void playbackFinished();
-	void playbackStopped();
-	void playbackChanged(bool playing);
-	void totalTimeChanged(int totalTime);
-	void currentTimeChanged(int currentTime);
-	void setMetadata(const QMap<MediaWidget::MetadataType, QString> &metadata);
-	void seekableChanged(bool seekable);
-	void audioChannelsChanged(const QStringList &audioChannels, int \
                currentAudioChannel);
-	void setCurrentAudioChannel(int currentAudioChannel);
-	void subtitlesChanged(const QStringList &subtitles, int currentSubtitle);
-	void setCurrentSubtitle(int currentSubtitle);
-	void dvdPlaybackChanged(bool playingDvd);
-	void titlesChanged(int titleCount, int currentTitle);
-	void setCurrentTitle(int currentTitle);
-	void chaptersChanged(int chapterCount, int currentChapter);
-	void setCurrentChapter(int currentChapter);
-	void anglesChanged(int angleCount, int currentAngle);
-	void setCurrentAngle(int currentAngle);
-	void videoSizeChanged();
+	void updatePlaybackStatus(MediaWidget::PlaybackStatus playbackStatus);
+	void updateTotalTime(int totalTime);
+	void updateCurrentTime(int currentTime);
+	void updateMetadata(const QMap<MediaWidget::MetadataType, QString> &metadata);
+	void updateSeekable(bool seekable);
+	void updateAudioChannels(const QStringList &audioChannels, int \
currentAudioChannel); +	void updateSubtitles(const QStringList &subtitles, int \
currentSubtitle); +	void updateTitles(int titleCount, int currentTitle);
+	void updateChapters(int chapterCount, int currentChapter);
+	void updateAngles(int angleCount, int currentAngle);
+	void updateDvdPlayback(bool playingDvd);
+	void updateVideoSize();
+
 	void checkScreenSaver();
 
 	void mutedChanged();
 	void volumeChanged(int volume);
+	void seek(int position);
 	void deinterlacingChanged(bool deinterlacing);
 	void aspectRatioChanged(QAction *action);
 	void autoResizeTriggered(QAction *action);
@@ -177,8 +197,10 @@ private slots:
 	void longSkipDurationChanged(int longSkipDuration);
 
 private:
-	void updateTimeButton();
-	void stopDvbPlayback();
+	void updateCurrentTotalTimeUi();
+	void updateSeekableUi();
+	void updateAudioChannelUi();
+	void updateSubtitleUi();
 
 	void contextMenuEvent(QContextMenuEvent *event);
 	void mouseDoubleClickEvent(QMouseEvent *event);
@@ -189,11 +211,9 @@ private:
 	void wheelEvent(QWheelEvent *event);
 
 	KMenu *menu;
-	XineMediaWidget *backend;
+	AbstractMediaWidget *backend;
 	OsdWidget *osdWidget;
-	DvbFeed *dvbFeed;
 
-	QString currentSourceName;
 	KAction *actionPrevious;
 	KAction *actionPlayPause;
 	QString textPlay;
@@ -202,21 +222,14 @@ private:
 	KIcon iconPause;
 	KAction *actionStop;
 	KAction *actionNext;
-	DisplayMode displayMode;
 	KAction *fullScreenAction;
 	KAction *minimalModeAction;
 	KComboBox *audioChannelBox;
 	KComboBox *subtitleBox;
 	QString textSubtitlesOff;
-	QList<KUrl> externalSubtitles;
-	KUrl currentExternalSubtitle;
-	bool audioChannelsReady;
-	bool subtitlesReady;
-	int autoResizeFactor;
 	KAction *muteAction;
 	KIcon mutedIcon;
 	KIcon unmutedIcon;
-	bool isMuted;
 	QSlider *volumeSlider;
 	SeekSlider *seekSlider;
 	KAction *longSkipBackwardAction;
@@ -234,8 +247,31 @@ private:
 	KMenu *navigationMenu;
 	KAction *jumpToPositionAction;
 	QPushButton *timeButton;
-	bool showElapsedTime;
+
+	PlaybackStatus backendPlaybackStatus;
+	DisplayMode displayMode;
+	ResizeFactor automaticResize;
+	Source source;
+	bool blockBackendUpdates;
+	bool muted;
 	bool screenSaverSuspended;
+
+	int backendTotalTime; // milliseconds
+	int backendCurrentTime; // milliseconds
+	bool showElapsedTime;
+	bool backendSeekable;
+
+	QStringList backendAudioChannels;
+	QStringList dvbAudioChannels;
+	int currentBackendAudioChannel; // first audio channel = 0
+	int currentDvbAudioChannel; // first audio channel = 0
+
+	QStringList backendSubtitles;
+	QStringList dvbSubtitles;
+	QList<KUrl> externalSubtitles;
+	int currentBackendSubtitle; // first subtitle = 0
+	int currentDvbSubtitle; // first subtitle = 0
+	int currentExternalSubtitle; // first subtitle = 0
 };
 
 #endif /* MEDIAWIDGET_H */
diff --git a/src/mediawidget_p.h b/src/mediawidget_p.h
index 26a6b1b..ce4d168 100644
--- a/src/mediawidget_p.h
+++ b/src/mediawidget_p.h
@@ -24,40 +24,9 @@
 #include <QSlider>
 #include <KDialog>
 
-class QSocketNotifier;
 class QTimeEdit;
 class MediaWidget;
 
-class DvbFeed : public QObject
-{
-	Q_OBJECT
-public:
-	explicit DvbFeed(QObject *parent);
-	~DvbFeed();
-
-	KUrl getUrl() const;
-	void writeData(const QByteArray &data);
-	void endOfData();
-
-	bool timeShiftPrepared;
-	bool timeShiftActive;
-	bool ignoreSourceChange;
-	QStringList audioChannels;
-	QStringList subtitles;
-
-private slots:
-	void readyWrite();
-
-private:
-	bool flush();
-
-	KUrl url;
-	int readFd;
-	int writeFd;
-	QSocketNotifier *notifier;
-	QList<QByteArray> buffers;
-};
-
 class JumpToPositionDialog : public KDialog
 {
 public:


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic