diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ad521f..7fc1c37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,89 +1,92 @@ cmake_minimum_required(VERSION 2.8.12) project(kmplayer) cmake_policy(VERSION 2.6) SET(KMPLAYER_MAJOR_VERSION "0") SET(KMPLAYER_MINOR_VERSION "12") SET(KMPLAYER_PATCH_VERSION "0b") SET(KMPLAYER_VERSION_STRING "${KMPLAYER_MAJOR_VERSION}.${KMPLAYER_MINOR_VERSION}.${KMPLAYER_PATCH_VERSION}") -find_package(ECM 1.2.0 REQUIRED NO_MODULE) +set(QT_MIN_VERSION "5.6.0") +set(KF5_MIN_VERSION "5.25.0") + +find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) #include(ECMSetupVersion) include(FeatureSummary) Include(CheckIncludeFiles) include(ECMSetupVersion) include(FindXCB) ecm_setup_version(${KMPLAYER_VERSION_STRING} VARIABLE_PREFIX KMPLAYERPRIVATE SOVERSION ${KMPLAYER_MAJOR_VERSION} ) -find_package(Qt5 REQUIRED COMPONENTS Core DBus Widgets Svg X11Extras) -find_package(KF5 REQUIRED COMPONENTS Config CoreAddons Init I18n KDELibs4Support KIO MediaPlayer Parts WidgetsAddons) -find_package(KF5DocTools) +find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core DBus Widgets Svg X11Extras) +find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Config CoreAddons Init I18n KDELibs4Support KIO MediaPlayer Parts WidgetsAddons) +find_package(KF5DocTools ${KF5_MIN_VERSION}) find_package(X11 REQUIRED) find_package(Phonon4Qt5 REQUIRED NO_MODULE) add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) if(NOT WIN32) OPTION(KMPLAYER_BUILT_WITH_CAIRO "Enable Cairo support" ON) OPTION(KMPLAYER_BUILT_WITH_NPP "Build NPP player" ON) OPTION(KMPLAYER_BUILT_WITH_EXPAT "Use expat XML parser" OFF) INCLUDE(UsePkgConfig) if (KMPLAYER_BUILT_WITH_CAIRO) PKGCONFIG(cairo CAIROIncDir CAIROLinkDir CAIROLinkFlags CAIROCflags) if (CAIROCflags) set(KMPLAYER_WITH_CAIRO 1) endif (CAIROCflags) endif (KMPLAYER_BUILT_WITH_CAIRO) if (KMPLAYER_BUILT_WITH_NPP) PKGCONFIG(dbus-glib-1 GLibDBusIncDir GLibDBusLinkDir GLibDBusLinkFlags GLibDBusCflags) PKGCONFIG(gmodule-2.0 GModuleIncDir GModuleLinkDir GModuleLinkFlags GModuleCflags) if (GLibDBusCflags) set(KMPLAYER_WITH_GDBUS 1) PKGCONFIG(gtk+-x11-2.0 GTKIncDir GTKLinkDir GTKLinkFlags GTKCflags) PKGCONFIG(gthread-2.0 GThreadIncDir GThreadLinkDir GThreadLinkFlags GThreadCflags) if (GTKCflags) set(KMPLAYER_WITH_NPP 1) endif (GTKCflags) endif (GLibDBusCflags) endif (KMPLAYER_BUILT_WITH_NPP) if (KMPLAYER_BUILT_WITH_EXPAT) INCLUDE(FindEXPAT) if (EXPAT_FOUND) set(KMPLAYER_WITH_EXPAT 1) else (EXPAT_FOUND) MESSAGE(Expat found) endif (EXPAT_FOUND) endif (KMPLAYER_BUILT_WITH_EXPAT) endif(NOT WIN32) check_include_files(stdint.h HAVE_STDINT_H) configure_file (config-kmplayer.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kmplayer.h ) add_subdirectory(src) add_subdirectory(icons) if (KF5DocTools_FOUND) add_subdirectory(doc) kdoctools_install(po) endif() add_subdirectory(data) ki18n_install(po) diff --git a/src/kmplayerbroadcast.cpp b/src/kmplayerbroadcast.cpp index 3ce9f21..0ae215e 100644 --- a/src/kmplayerbroadcast.cpp +++ b/src/kmplayerbroadcast.cpp @@ -1,670 +1,666 @@ /* this file is part of the kmplayer application copyright (c) 2003 koos vriezen 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; see the file copying. if not, write to the free software foundation, inc., 59 temple place - suite 330, boston, ma 02111-1307, usa. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmplayerbroadcast.h" #include "kmplayerprocess.h" #include "kmplayerview.h" #include "kmplayerpartbase.h" static const char * strBroadcast = "Broadcast"; static const char * strBindAddress = "Bind Address"; static const char * strFFServerPort = "FFServer Port"; static const char * strMaxClients = "Maximum Connections"; static const char * strMaxBandwidth = "Maximum Bandwidth"; static const char * strFeedFile = "Feed File"; static const char * strFeedFileSize = "Feed File Size"; //static const char * strFFServerSetting = "FFServer Setting"; static const char * strFFServerCustomSetting = "Custom Setting"; static const char * strFFServerProfiles = "Profiles"; KDE_NO_CDTOR_EXPORT FFServerSetting::FFServerSetting (int i, const QString & n, const QString & f, const QString & ac, int abr, int asr, const QString & vc, int vbr, int q, int fr, int gs, int w, int h) : index (i), name (n), format (f), audiocodec (ac), audiobitrate (abr > 0 ? QString::number (abr) : QString ()), audiosamplerate (asr > 0 ? QString::number (asr) : QString ()), videocodec (vc), videobitrate (vbr > 0 ? QString::number (vbr) : QString ()), quality (q > 0 ? QString::number (q) : QString ()), framerate (fr > 0 ? QString::number (fr) : QString ()), gopsize (gs > 0 ? QString::number (gs) : QString ()), width (w > 0 ? QString::number (w) : QString ()), height (h > 0 ? QString::number (h) : QString ()) {} KDE_NO_EXPORT FFServerSetting & FFServerSetting::operator = (const FFServerSetting & fs) { format = fs.format; audiocodec = fs.audiocodec; audiobitrate = fs.audiobitrate; audiosamplerate = fs.audiosamplerate; videocodec = fs.videocodec; videobitrate = fs.videobitrate; quality = fs.quality; framerate = fs.framerate; gopsize = fs.gopsize; width = fs.width; height = fs.height; return *this; } KDE_NO_EXPORT FFServerSetting & FFServerSetting::operator = (const QStringList & sl) { if (sl.count () < 11) { return *this; } QStringList::const_iterator it = sl.begin (); format = *it++; audiocodec = *it++; audiobitrate = *it++; audiosamplerate = *it++; videocodec = *it++; videobitrate = *it++; quality = *it++; framerate = *it++; gopsize = *it++; width = *it++; height = *it++; acl.clear (); QStringList::const_iterator end( sl.end() ); for (; it != end; ++it) acl.push_back (*it); return *this; } KDE_NO_EXPORT QString & FFServerSetting::ffconfig (QString & buf) { QString nl ("\n"); buf = QString ("Format ") + format + nl; if (!audiocodec.isEmpty ()) buf += QString ("AudioCodec ") + audiocodec + nl; if (!audiobitrate.isEmpty ()) buf += QString ("AudioBitRate ") + audiobitrate + nl; if (!audiosamplerate.isEmpty () > 0) buf += QString ("AudioSampleRate ") + audiosamplerate + nl; if (!videocodec.isEmpty ()) buf += QString ("VideoCodec ") + videocodec + nl; if (!videobitrate.isEmpty ()) buf += QString ("VideoBitRate ") + videobitrate + nl; if (!quality.isEmpty ()) buf += QString ("VideoQMin ") + quality + nl; if (!framerate.isEmpty ()) buf += QString ("VideoFrameRate ") + framerate + nl; if (!gopsize.isEmpty ()) buf += QString ("VideoGopSize ") + gopsize + nl; if (!width.isEmpty () && !height.isEmpty ()) buf += QString ("VideoSize ") + width + QString ("x") + height + nl; return buf; } KDE_NO_EXPORT const QStringList FFServerSetting::list () { QStringList sl; sl.push_back (format); sl.push_back (audiocodec); sl.push_back (audiobitrate); sl.push_back (audiosamplerate); sl.push_back (videocodec); sl.push_back (videobitrate); sl.push_back (quality); sl.push_back (framerate); sl.push_back (gopsize); sl.push_back (width); sl.push_back (height); QStringList::const_iterator it = acl.begin (); QStringList::const_iterator end( acl.end () ); for (; it != end; ++it) sl.push_back (*it); return sl; } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT KMPlayerPrefBroadcastPage::KMPlayerPrefBroadcastPage (QWidget *parent) : QFrame (parent) { QVBoxLayout *layout = new QVBoxLayout (this, 5); QGridLayout *gridlayout = new QGridLayout (layout, 6, 2, 2); QLabel *label = new QLabel (i18n ("Bind address:"), this); bindaddress = new QLineEdit ("", this); QWhatsThis::add (bindaddress, i18n ("If you have multiple network devices, you can limit access")); gridlayout->addWidget (label, 0, 0); gridlayout->addWidget (bindaddress, 0, 1); label = new QLabel (i18n ("Listen port:"), this); port = new QLineEdit ("", this); gridlayout->addWidget (label, 1, 0); gridlayout->addWidget (port, 1, 1); label = new QLabel (i18n ("Maximum connections:"), this); maxclients = new QLineEdit ("", this); gridlayout->addWidget (label, 2, 0); gridlayout->addWidget (maxclients, 2, 1); label = new QLabel (i18n ("Maximum bandwidth (kbit):"), this); maxbandwidth = new QLineEdit ("", this); gridlayout->addWidget (label, 3, 0); gridlayout->addWidget (maxbandwidth, 3, 1); label = new QLabel (i18n ("Temporary feed file:"), this); feedfile = new QLineEdit ("", this); gridlayout->addWidget (label, 4, 0); gridlayout->addWidget (feedfile, 4, 1); label = new QLabel (i18n ("Feed file size (kB):"), this); feedfilesize = new QLineEdit ("", this); gridlayout->addWidget (label, 5, 0); gridlayout->addWidget (feedfilesize, 5, 1); layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); } //----------------------------------------------------------------------------- #undef ADDPROPERTY #define ADDPROPERTY(label,qedit,gridlayout,row,parent) \ qedit = new QLineEdit ("", parent); \ gridlayout->addWidget (new QLabel (qedit, label, parent), row, 0); \ gridlayout->addWidget (qedit, row, 1); KDE_NO_CDTOR_EXPORT KMPlayerPrefBroadcastFormatPage::KMPlayerPrefBroadcastFormatPage (QWidget *parent, FFServerSettingList & ffs) : QFrame (parent, "BroadcastPage"), profiles (ffs) { QHBoxLayout *layout = new QHBoxLayout (this, 5); QGridLayout *formatlayout = new QGridLayout (11, 2, 2); formatlayout->setAlignment (Qt::AlignTop); QVBoxLayout *leftlayout = new QVBoxLayout (15); QHBoxLayout *ledlayout = new QHBoxLayout (5); format = new QComboBox (this); QLabel * label = new QLabel (format, i18n ("Format:"), this); format->clear (); format->insertItem (QString ("asf")); format->insertItem (QString ("avi")); format->insertItem (QString ("mpjpeg")); format->insertItem (QString ("mpeg")); format->insertItem (QString ("rm")); format->insertItem (QString ("swf")); QWhatsThis::add (format, i18n ("Only avi, mpeg and rm work for mplayer playback")); formatlayout->addWidget (label, 0, 0); formatlayout->addWidget (format, 0, 1); ADDPROPERTY (i18n ("Audio codec:"), audiocodec, formatlayout, 1, this); ADDPROPERTY (i18n ("Audio bit rate (kbit):"), audiobitrate, formatlayout, 2, this); ADDPROPERTY (i18n ("Audio sample rate (Hz):"), audiosamplerate, formatlayout, 3, this); ADDPROPERTY (i18n ("Video codec:"), videocodec, formatlayout, 4, this); ADDPROPERTY (i18n ("Video bit rate (kbit):"), videobitrate, formatlayout, 5, this); ADDPROPERTY (i18n ("Quality (1-31):"), quality, formatlayout, 6, this); ADDPROPERTY (i18n ("Frame rate (Hz):"), framerate, formatlayout, 7, this); ADDPROPERTY (i18n ("Gop size:"), gopsize, formatlayout, 8, this); ADDPROPERTY (i18n ("Width (pixels):"), moviewidth, formatlayout, 9, this); ADDPROPERTY (i18n ("Height (pixels):"), movieheight, formatlayout, 10, this); label = new QLabel (i18n ("Allow access from:"), this); accesslist = new QTable (40, 1, this); accesslist->verticalHeader ()->hide (); accesslist->setLeftMargin (0); accesslist->setColumnWidth (0, 250); QWhatsThis::add (accesslist, i18n ("'Single IP' or 'start-IP end-IP' for IP ranges")); QHeader *header = accesslist->horizontalHeader (); header->setLabel (0, i18n ("Host/IP or IP Range")); QFrame *profileframe = new QFrame (this); QGridLayout *profileslayout = new QGridLayout (profileframe, 5, 2, 2); profile = new QLineEdit ("", profileframe); connect (profile, SIGNAL(textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &))); profilelist = new QListBox (profileframe); for (int i = 0; i < (int) profiles.size (); i++) profilelist->insertItem (profiles[i]->name, i); connect (profilelist, SIGNAL (selected (int)), this, SLOT (slotIndexChanged (int))); connect (profilelist, SIGNAL (highlighted (int)), this, SLOT (slotItemHighlighted (int))); load = new QPushButton (i18n ("Load"), profileframe); save = new QPushButton (i18n ("Save"), profileframe); del = new QPushButton (i18n ("Delete"), profileframe); load->setEnabled (false); save->setEnabled (false); del->setEnabled (false); connect (load, SIGNAL (clicked ()), this, SLOT (slotLoad ())); connect (save, SIGNAL (clicked ()), this, SLOT (slotSave ())); connect (del, SIGNAL (clicked ()), this, SLOT (slotDelete ())); profileslayout->addWidget (profile, 0, 0); -#if (QT_VERSION < 0x030200) - profileslayout->addRowSpacing (4, 60); -#else profileslayout->setRowSpacing (4, 60); -#endif profileslayout->addMultiCellWidget (profilelist, 1, 4, 0, 0); profileslayout->addWidget (load, 1, 1); profileslayout->addWidget (save, 2, 1); profileslayout->addWidget (del, 3, 1); leftlayout->addWidget (profileframe); startbutton = new QPushButton (i18n ("Start"), this); serverled = new KLed (Qt::green, KLed::Off, KLed::Raised, KLed::Circular, this); feedled = new KLed (Qt::green, KLed::Off, KLed::Raised, KLed::Circular, this); ledlayout->addWidget (startbutton); ledlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); ledlayout->addWidget (serverled); ledlayout->addWidget (feedled); leftlayout->addLayout (ledlayout); QFrame * line = new QFrame (this); line->setFrameShape (QFrame::HLine); leftlayout->addWidget (line); leftlayout->addWidget (label); leftlayout->addWidget (accesslist); leftlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); layout->addLayout (leftlayout); line = new QFrame (this); line->setFrameShape (QFrame::VLine); layout->addWidget (line); layout->addLayout (formatlayout); layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); } #undef ADDPROPERTY KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::setSettings (const FFServerSetting & fs) { if (!fs.format.isEmpty ()) format->setCurrentText (fs.format); audiocodec->setText (fs.audiocodec); audiobitrate->setText (fs.audiobitrate); audiosamplerate->setText (fs.audiosamplerate); videocodec->setText (fs.videocodec); videobitrate->setText (fs.videobitrate); quality->setText (fs.quality); framerate->setText (fs.framerate); gopsize->setText (fs.gopsize); moviewidth->setText (fs.width); movieheight->setText (fs.height); accesslist->setNumRows (0); accesslist->setNumRows (50); QStringList::const_iterator it = fs.acl.begin (); QStringList::const_iterator end( fs.acl.end () ); for (int i = 0; it != end; ++i, ++it) accesslist->setItem (i, 0, new QTableItem (accesslist, QTableItem::Always, *it)); } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::getSettings (FFServerSetting & fs) { fs.format = format->currentText (); fs.audiocodec = audiocodec->text (); fs.audiobitrate = audiobitrate->text (); fs.audiosamplerate = audiosamplerate->text (); fs.videocodec = videocodec->text (); fs.videobitrate = videobitrate->text (); fs.quality = quality->text (); fs.framerate = framerate->text (); fs.gopsize = gopsize->text (); fs.width = moviewidth->text (); fs.height = movieheight->text (); fs.acl.clear (); for (int i = 0; i < accesslist->numRows (); ++i) { if (accesslist->item (i, 0) && !accesslist->item (i, 0)->text ().isEmpty ()) fs.acl.push_back (accesslist->item (i, 0)->text ()); } } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotIndexChanged (int index) { slotItemHighlighted (index); if (index >= 0 && index < (int) profiles.size ()) setSettings (*profiles[index]); } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotTextChanged (const QString & txt) { save->setEnabled (txt.size ()); } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotItemHighlighted (int index) { if (index < 0 || index >= (int) profiles.size ()) { load->setEnabled (false); del->setEnabled (false); } else { profile->setText (profiles[profilelist->currentItem ()]->name); load->setEnabled (true); del->setEnabled (true); slotTextChanged (profilelist->currentText ()); } } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotSave () { for (int i = 0; i < (int) profiles.size (); ++i) if (profiles[i]->name == profile->text ()) { getSettings (*profiles[i]); return; } FFServerSetting * fs = new FFServerSetting; fs->name = profile->text (); getSettings (*fs); profiles.push_back (fs); profilelist->insertItem (fs->name); } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotLoad () { setSettings (*profiles[profilelist->currentItem ()]); } KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotDelete () { FFServerSettingList::iterator it = profiles.begin(); for (int i = 0; i < profilelist->currentItem (); i++) ++it; delete *it; profiles.erase (it); profilelist->removeItem (profilelist->currentItem ()); load->setEnabled (false); del->setEnabled (false); } //----------------------------------------------------------------------------- static bool stopProcess (KProcess * process, const char * cmd = 0L) { if (!process || !process->isRunning ()) return true; do { if (cmd) process->writeStdin (cmd, strlen (cmd)); KProcessController::theKProcessController->waitForProcessExit (1); if (!process->isRunning ()) break; process->kill (SIGINT); KProcessController::theKProcessController->waitForProcessExit (3); if (!process->isRunning ()) break; process->kill (SIGTERM); KProcessController::theKProcessController->waitForProcessExit (1); if (!process->isRunning ()) break; process->kill (SIGKILL); KProcessController::theKProcessController->waitForProcessExit (1); if (process->isRunning ()) { return false; // give up } } while (false); return true; } KDE_NO_CDTOR_EXPORT KMPlayerBroadcastConfig::KMPlayerBroadcastConfig (KMPlayer::PartBase * player, KMPlayerFFServerConfig * fsc) : m_player (player), m_ffserverconfig (fsc), m_ffmpeg_process (0L), m_ffserver_process (0L), m_endserver (true) { } KDE_NO_CDTOR_EXPORT KMPlayerBroadcastConfig::~KMPlayerBroadcastConfig () { stopServer (); } KDE_NO_EXPORT void KMPlayerBroadcastConfig::write (KConfig * config) { config->setGroup (strBroadcast); config->writeEntry (strFFServerCustomSetting, ffserversettings.list (), ';'); QStringList sl; for (int i = 0; i < (int) ffserversettingprofiles.size (); i++) { sl.push_back (ffserversettingprofiles[i]->name); config->writeEntry (QString ("Profile_") + ffserversettingprofiles[i]->name, ffserversettingprofiles[i]->list(), ';'); } config->writeEntry (strFFServerProfiles, sl, ';'); } KDE_NO_EXPORT void KMPlayerBroadcastConfig::read (KConfig * config) { std::for_each (ffserversettingprofiles.begin (), ffserversettingprofiles.end (), KMPlayer::Deleter()); ffserversettingprofiles.clear (); config->setGroup (strBroadcast); ffserversettings = config->readListEntry (strFFServerCustomSetting, ';'); QStringList profiles = config->readListEntry (strFFServerProfiles, ';'); QStringList::iterator pr_it = profiles.begin (); QStringList::iterator pr_end( profiles.end () ); for (; pr_it != pr_end; ++pr_it) { QStringList sl = config->readListEntry (QString ("Profile_") + *pr_it, ';'); if (sl.size () > 10) { FFServerSetting * ffs = new FFServerSetting (sl); ffs->name = *pr_it; ffserversettingprofiles.push_back (ffs); } } } KDE_NO_EXPORT void KMPlayerBroadcastConfig::sync (bool fromUI) { if (fromUI) { m_configpage->getSettings(ffserversettings); } else { m_configpage->setSettings (ffserversettings); m_configpage->profile->setText (QString ()); } } KDE_NO_EXPORT void KMPlayerBroadcastConfig::prefLocation (QString & item, QString & icon, QString & tab) { item = i18n ("Broadcasting"); icon = QString ("share"); tab = i18n ("Profiles"); } QFrame * KMPlayerBroadcastConfig::prefPage (QWidget * parent) { if (!m_configpage) { m_configpage = new KMPlayerPrefBroadcastFormatPage (parent, ffserversettingprofiles); connect (m_configpage->startbutton, SIGNAL (clicked ()), this, SLOT (startServer ())); connect (m_player, SIGNAL (sourceChanged (KMPlayer::Source *, KMPlayer::Source *)), this, SLOT (sourceChanged (KMPlayer::Source *,KMPlayer::Source *))); m_configpage->startbutton->setEnabled (!m_player->source ()->videoDevice ().isEmpty ()); } return m_configpage; } KDE_NO_EXPORT bool KMPlayerBroadcastConfig::broadcasting () const { return m_ffserver_process && m_ffserver_process->isRunning (); } #include #include static const char ffserverconf[] = "Port %d\nBindAddress %s\nMaxClients %d\nMaxBandwidth %d\n" "CustomLog -\nNoDaemon\n" "\nFile %s\nFileMaxSize %dK\nACL allow 127.0.0.1\n\n" "\nFeed kmplayer.ffm\n%s\n%s%s\n\n" "\nFormat status\nACL allow localhost\n\n"; KDE_NO_EXPORT void KMPlayerBroadcastConfig::startServer () { if (broadcasting ()) { stopServer (); return; } m_configpage->setCursor (QCursor (Qt::WaitCursor)); m_ffserver_process = new KProcess; m_ffserver_process->setUseShell (true); connect (m_ffserver_process, SIGNAL (processExited (KProcess *)), this, SLOT (processStopped (KProcess *))); QString conffile = KStandardDirs::locateLocal ("data", "kmplayer/ffserver.conf"); const char * noaudio = m_player->source ()->audioDevice ().isEmpty () ? "NoAudio" : ""; FFServerSetting ffs; m_configpage->getSettings (ffs); QString acl; QStringList::iterator it = ffs.acl.begin (); QStringList::iterator end( ffs.acl.end () ); for (; it != end; ++it) acl += QString ("ACL allow ") + *it + QString ("\n"); unlink (m_ffserverconfig->feedfile.ascii ()); QFile qfile (conffile); qfile.open (IO_WriteOnly); QString configdata; QString buf; configdata.sprintf (ffserverconf, m_ffserverconfig->ffserverport, m_ffserverconfig->bindaddress.ascii (), m_ffserverconfig->maxclients, m_ffserverconfig->maxbandwidth, m_ffserverconfig->feedfile.ascii (), m_ffserverconfig->feedfilesize, ffs.format.ascii (), acl.ascii (), ffs.ffconfig (buf).ascii (), noaudio); qfile.writeBlock (configdata.ascii (), configdata.size ()); qfile.close (); kdDebug () << configdata << endl; kdDebug () << "ffserver -f " << conffile << endl; *m_ffserver_process << "ffserver -f " << conffile; m_ffserver_out.truncate (0); connect (m_ffserver_process, SIGNAL (receivedStderr (KProcess *, char *, int)), this, SLOT (processOutput (KProcess *, char *, int))); m_ffserver_process->start (KProcess::NotifyOnExit, KProcess::Stderr); if (m_ffserver_process->isRunning ()) { m_configpage->startbutton->setText (i18n ("Stop")); m_configpage->serverled->setState (KLed::On); emit broadcastStarted (); } QTimer::singleShot (500, this, SLOT (startFeed ())); } KDE_NO_EXPORT void KMPlayerBroadcastConfig::stopServer () { m_endserver = true; if (m_ffmpeg_process) m_ffmpeg_process->stop (); if (!stopProcess (m_ffserver_process)) KMessageBox::error (m_configpage, i18n ("Failed to end ffserver process."), i18n ("Error")); } KDE_NO_EXPORT void KMPlayerBroadcastConfig::processOutput (KProcess * p, char * s, int) { if (p == m_ffserver_process) m_ffserver_out += QString (s); } KDE_NO_EXPORT void KMPlayerBroadcastConfig::startFeed () { if (!m_configpage) { stopServer (); return; } FFServerSetting ffs; m_configpage->getSettings (ffs); QString ffurl; if (!m_ffserver_process || !m_ffserver_process->isRunning ()) { KMessageBox::error (m_configpage, i18n ("Failed to start ffserver.\n") + m_ffserver_out, i18n ("Error")); goto bail_out; } disconnect (m_ffserver_process, SIGNAL (receivedStderr (KProcess *, char *, int)), this, SLOT (processOutput (KProcess *, char *, int))); if (m_ffmpeg_process) m_ffmpeg_process->stop (); delete m_ffmpeg_process; m_ffmpeg_process = new KMPlayer::FFMpeg (m_player, NULL, m_player->settings ()); connect (m_ffmpeg_process, SIGNAL (stateChange (KMPlayer::Process::State, KMPlayer::Process::State)), this, SLOT (stateChange (KMPlayer::Process::State, KMPlayer::Process::State))); ffurl.sprintf ("http://localhost:%d/kmplayer.ffm", m_ffserverconfig->ffserverport); //m_ffmpeg_process->setUrl (KUrl(ffurl)); if (!m_ffmpeg_process->play ()) { KMessageBox::error (m_configpage, i18n ("Failed to start ffmpeg."), i18n ("Error")); stopProcess (m_ffserver_process); goto bail_out; } if (m_ffmpeg_process->running ()) { m_ffserver_url.sprintf ("http://localhost:%d/video.%s", m_ffserverconfig->ffserverport, ffs.format.ascii ()); m_endserver = false; m_configpage->feedled->setState (KLed::On); m_player->openUrl (KUrl (m_ffserver_url)); } else stopServer (); bail_out: m_configpage->setCursor (QCursor (Qt::ArrowCursor)); } /* KDE_NO_EXPORT void KMPlayerBroadcastConfig::stateChange (KMPlayer::Process::State old, KMPlayer::Process::State state) { if (state < KMPlayer::Process::Buffering && old >KMPlayer::Process::Ready) { if (m_configpage) m_configpage->feedled->setState (KLed::Off); m_ffmpeg_process->deleteLater (); m_ffmpeg_process = 0L; kdDebug () << "ffmpeg process stopped " << m_endserver << endl; if (m_endserver && !stopProcess (m_ffserver_process)) { disconnect (m_ffserver_process, SIGNAL (receivedStderr (KProcess *, char *, int)), this, SLOT (processOutput (KProcess *, char *, int))); KMessageBox::error (m_configpage, i18n ("Failed to end ffserver process."), i18n ("Error")); processStopped (0L); } } } */ KDE_NO_EXPORT void KMPlayerBroadcastConfig::processStopped (KProcess *) { kdDebug () << "ffserver process stopped" << endl; if (m_configpage) { m_configpage->serverled->setState (KLed::Off); m_configpage->startbutton->setText (i18n ("Start")); m_configpage->startbutton->setEnabled (!m_player->source ()->videoDevice ().isEmpty ()); } m_ffserver_process->deleteLater (); m_ffserver_process = 0L; emit broadcastStopped (); } KDE_NO_EXPORT void KMPlayerBroadcastConfig::sourceChanged (KMPlayer::Source *, KMPlayer::Source * source) { if (m_configpage) m_configpage->startbutton->setEnabled (broadcasting () || (source && !source->videoDevice ().isEmpty ())); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT KMPlayerFFServerConfig::KMPlayerFFServerConfig () { } KDE_NO_EXPORT void KMPlayerFFServerConfig::write (KConfig * config) { config->setGroup (strBroadcast); config->writeEntry (strBindAddress, bindaddress); config->writeEntry (strFFServerPort, ffserverport); config->writeEntry (strMaxClients, maxclients); config->writeEntry (strMaxBandwidth, maxbandwidth); config->writePathEntry (strFeedFile, feedfile); config->writeEntry (strFeedFileSize, feedfilesize); } KDE_NO_EXPORT void KMPlayerFFServerConfig::read (KConfig * config) { config->setGroup (strBroadcast); bindaddress = config->readEntry (strBindAddress, "0.0.0.0"); ffserverport = config->readNumEntry (strFFServerPort, 8090); maxclients = config->readNumEntry (strMaxClients, 10); maxbandwidth = config->readNumEntry (strMaxBandwidth, 1000); feedfile = config->readPathEntry (strFeedFile, "/tmp/kmplayer.ffm"); feedfilesize = config->readNumEntry (strFeedFileSize, 512); } KDE_NO_EXPORT void KMPlayerFFServerConfig::sync (bool fromUI) { if (fromUI) { bindaddress = m_configpage->bindaddress->text (); ffserverport = m_configpage->port->text ().toInt (); maxclients = m_configpage->maxclients->text ().toInt (); maxbandwidth = m_configpage->maxbandwidth->text ().toInt(); feedfile = m_configpage->feedfile->text (); feedfilesize = m_configpage->feedfilesize->text ().toInt(); } else { m_configpage->bindaddress->setText (bindaddress); m_configpage->port->setText (QString::number (ffserverport)); m_configpage->maxclients->setText (QString::number (maxclients)); m_configpage->maxbandwidth->setText (QString::number (maxbandwidth)); m_configpage->feedfile->setText (feedfile); m_configpage->feedfilesize->setText (QString::number (feedfilesize)); } } KDE_NO_EXPORT void KMPlayerFFServerConfig::prefLocation (QString & item, QString & icon, QString & tab) { item = i18n ("Broadcasting"); icon = QString ("share"); tab = i18n ("FFServer"); } KDE_NO_EXPORT QFrame *KMPlayerFFServerConfig::prefPage (QWidget * parent) { if (!m_configpage) m_configpage = new KMPlayerPrefBroadcastPage (parent); return m_configpage; } #include "kmplayerbroadcast.moc" diff --git a/src/kmplayercontrolpanel.cpp b/src/kmplayercontrolpanel.cpp index 2278bfe..6a16fa8 100644 --- a/src/kmplayercontrolpanel.cpp +++ b/src/kmplayercontrolpanel.cpp @@ -1,753 +1,751 @@ /** * Copyright (C) 2005 by Koos Vriezen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, * Boston, MA 02110-1301, USA. **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmplayerview.h" #include "kmplayercontrolpanel.h" static const int button_height_with_slider = 16; static const int button_height_only_buttons = 16; static float dpi_scale = 1.0; #include "kmplayerview.h" #include "kmplayercontrolpanel.h" using namespace KMPlayer; static char xpm_fg_color [32] = ". c #000000"; static const char * stop_xpm[] = { "5 7 2 1", " c None", xpm_fg_color, " ", ".....", ".....", ".....", ".....", ".....", " "}; static const char * play_xpm[] = { "5 9 2 1", " c None", xpm_fg_color, ". ", ".. ", "... ", ".... ", ".....", ".... ", "... ", ".. ", ". "}; static const char * pause_xpm[] = { "7 9 2 1", " c None", xpm_fg_color, " ", ".. ..", ".. ..", ".. ..", ".. ..", ".. ..", ".. ..", ".. ..", " "}; static const char * forward_xpm[] = { "11 9 2 1", " c None", xpm_fg_color, ". . ", ".. .. ", "... ... ", ".... .... ", "..... .....", ".... .... ", "... ... ", ".. .. ", ". . "}; static const char * back_xpm[] = { "11 9 2 1", " c None", xpm_fg_color, " . .", " .. ..", " ... ...", " .... ....", "..... .....", " .... ....", " ... ...", " .. ..", " . ."}; static const char * config_xpm[] = { "11 8 2 1", " c None", xpm_fg_color, " ", " ", "...........", " ......... ", " ....... ", " ..... ", " ... ", " . "}; static const char *playlist_xpm[] = { "8 9 2 1", " c None", xpm_fg_color, " ", " ", "........", "........", " ", " ", "........", "........", " "}; static const char *normal_window_xpm[] = { "7 9 2 1", " c None", xpm_fg_color, " ", ".......", ".......", ". .", ". .", ". .", ". .", ".......", " "}; static const char * record_xpm[] = { "7 7 3 1", " c None", xpm_fg_color, "+ c #FF0000", " ", ".......", ".+++++.", ".+++++.", ".+++++.", ".......", " "}; static const char * broadcast_xpm[] = { "21 9 2 1", " c None", xpm_fg_color, " ", " .. .. .. .. ", ".. .. ... .. ..", ".. .. ..... .. ..", ".. .. ..... .. ..", ".. .. ..... .. ..", ".. .. ... .. ..", " .. .. .. .. ", " "}; static const char * language_xpm [] = { "12 9 2 1", " c None", xpm_fg_color, " ", " ", " ", " ", " ", ".... ......", ".... ......", ".... ......", " "}; static const char * red_xpm[] = { "7 9 3 1", " c None", xpm_fg_color, "+ c #FF0000", " ", ".......", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".......", " "}; static const char * green_xpm[] = { "7 9 3 1", " c None", xpm_fg_color, "+ c #00FF00", " ", ".......", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".......", " "}; static const char * yellow_xpm[] = { "7 9 3 1", " c None", xpm_fg_color, "+ c #FFFF00", " ", ".......", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".......", " "}; static const char * blue_xpm[] = { "7 9 3 1", " c None", xpm_fg_color, "+ c #0080FF00", " ", ".......", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".+++++.", ".......", " "}; //----------------------------------------------------------------------------- static QIcon makeIcon(const char** xpm) { QPixmap pix(xpm); if (dpi_scale > 1.01) pix = pix.scaledToHeight(pix.height() * dpi_scale, Qt::SmoothTransformation); return QIcon(pix); } static QPushButton *ctrlButton(QBoxLayout* l, const char **p, int key = 0) { QPushButton* b = new QPushButton(makeIcon(p), QString()); b->setFocusPolicy (Qt::NoFocus); b->setFlat (true); b->setAutoFillBackground (true); if (key) b->setShortcut (QKeySequence (key)); l->addWidget (b); return b; } KDE_NO_CDTOR_EXPORT KMPlayerMenuButton::KMPlayerMenuButton(QWidget*, QBoxLayout * l, const char ** p, int key) : QPushButton(makeIcon(p), QString()) { setFocusPolicy (Qt::NoFocus); setFlat (true); setAutoFillBackground (true); if (key) setShortcut (QKeySequence (key)); l->addWidget (this); } KDE_NO_EXPORT void KMPlayerMenuButton::enterEvent (QEvent *) { emit mouseEntered (); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT KMPlayerPopupMenu::KMPlayerPopupMenu (QWidget *parent, const QString &title) : QMenu(title, parent) {} KDE_NO_EXPORT void KMPlayerPopupMenu::leaveEvent (QEvent *) { emit mouseLeft (); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT VolumeBar::VolumeBar(QWidget*, View * view) : m_view(view), m_value(100) { setSizePolicy( QSizePolicy (QSizePolicy::Minimum, QSizePolicy::Fixed)); setMinimumSize (QSize (51, button_height_only_buttons + 2)); setToolTip (i18n ("Volume is ") + QString::number (m_value)); setAutoFillBackground (true); QPalette palette; palette.setColor (backgroundRole (), m_view->palette ().color (QPalette::Background)); setPalette (palette); } KDE_NO_CDTOR_EXPORT VolumeBar::~VolumeBar () { } void VolumeBar::setValue (int v) { m_value = v; if (m_value < 0) m_value = 0; if (m_value > 100) m_value = 100; setToolTip (i18n ("Volume is ") + QString::number (m_value)); repaint (); emit volumeChanged (m_value); } void VolumeBar::wheelEvent (QWheelEvent * e) { setValue (m_value + (e->delta () > 0 ? 2 : -2)); e->accept (); } void VolumeBar::paintEvent (QPaintEvent * e) { QWidget::paintEvent (e); QPainter p; p.begin (this); QColor color = palette ().color (foregroundRole ()); p.setPen (color); int w = width () - 6 * dpi_scale; int vx = m_value * w / 100; p.fillRect (3 * dpi_scale, 3 * dpi_scale, vx, 7 * dpi_scale, color); p.drawRect (vx + 3 * dpi_scale, 3 * dpi_scale, w - vx, 7 * dpi_scale); p.end (); //kDebug () << "w=" << w << " vx=" << vx; } void VolumeBar::mousePressEvent (QMouseEvent * e) { setValue (100 * (e->x () - 3 * dpi_scale) / (width () - 6 * dpi_scale)); e->accept (); } void VolumeBar::mouseMoveEvent (QMouseEvent * e) { setValue (100 * (e->x () - 3 * dpi_scale) / (width () - 6 * dpi_scale)); e->accept (); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT ControlPanel::ControlPanel(QWidget * parent, View * view) : QWidget (parent), m_progress_mode (progress_playing), m_progress_length (0), m_popup_timer (0), m_popdown_timer (0), m_view (view), m_auto_controls (true), m_popup_clicked (false) { -#if QT_VERSION > 0x040399 setAttribute (Qt::WA_NativeWindow); setAttribute(Qt::WA_DontCreateNativeAncestors); -#endif dpi_scale = qMax(1.0, logicalDpiX() / 120.0); m_buttonbox = new QHBoxLayout (this); m_buttonbox->setSpacing (4 * dpi_scale); m_buttonbox->setContentsMargins (5 * dpi_scale, 5 * dpi_scale, 5 * dpi_scale, 5 * dpi_scale); setAutoFillBackground (true); QColor c = palette ().color (foregroundRole ()); strncpy (xpm_fg_color, QString().sprintf(". c #%02x%02x%02x", c.red(), c.green(),c.blue()).toAscii().constData(), 31); xpm_fg_color[31] = 0; m_buttons[button_config] = new KMPlayerMenuButton (this, m_buttonbox, config_xpm); m_buttons[button_playlist] = ctrlButton(m_buttonbox, playlist_xpm); m_buttons[button_back] = ctrlButton(m_buttonbox, back_xpm); m_buttons[button_play] = ctrlButton(m_buttonbox, play_xpm, Qt::Key_R); m_buttons[button_forward] = ctrlButton(m_buttonbox, forward_xpm); m_buttons[button_stop] = ctrlButton(m_buttonbox, stop_xpm, Qt::Key_S); m_buttons[button_pause]=ctrlButton(m_buttonbox, pause_xpm, Qt::Key_P); m_buttons[button_record] = ctrlButton(m_buttonbox, record_xpm); m_buttons[button_broadcast] = ctrlButton(m_buttonbox, broadcast_xpm); m_buttons[button_language] = new KMPlayerMenuButton (this, m_buttonbox, language_xpm); m_buttons[button_red] = ctrlButton(m_buttonbox, red_xpm); m_buttons[button_green] = ctrlButton(m_buttonbox, green_xpm); m_buttons[button_yellow] = ctrlButton(m_buttonbox, yellow_xpm); m_buttons[button_blue] = ctrlButton(m_buttonbox, blue_xpm); m_buttons[button_play]->setCheckable (true); m_buttons[button_stop]->setCheckable (true); m_buttons[button_record]->setCheckable (true); m_buttons[button_broadcast]->setCheckable (true); m_posSlider = new QSlider; m_posSlider->setOrientation (Qt::Horizontal); m_posSlider->setMaximum (100); m_posSlider->setPageStep (1); m_posSlider->setEnabled (false); m_buttonbox->addWidget (m_posSlider); setupPositionSlider (true); m_volume = new VolumeBar (this, m_view); m_buttonbox->addWidget (m_volume); popupMenu = new KMPlayerPopupMenu (this, QString ()); playerMenu = new KMPlayerPopupMenu (this, i18n ("&Play with")); playersAction = popupMenu->addMenu (playerMenu); videoConsoleAction = popupMenu->addAction(QIcon::fromTheme("utilities-terminal"), i18n("Con&sole")); playlistAction = popupMenu->addAction(QIcon::fromTheme("view-media-playlist"), i18n("Play&list")); zoomMenu = new KMPlayerPopupMenu (this, i18n ("&Zoom")); zoomAction = popupMenu->addMenu (zoomMenu); zoomAction->setIcon(QIcon::fromTheme("zoom-fit-best")); zoom50Action = zoomMenu->addAction (i18n ("50%")); zoom100Action = zoomMenu->addAction (i18n ("100%")); zoom150Action = zoomMenu->addAction (i18n ("150%")); fullscreenAction = popupMenu->addAction(QIcon::fromTheme("view-fullscreen"), i18n("&Full Screen")); fullscreenAction->setShortcut (QKeySequence (Qt::Key_F)); popupMenu->addSeparator (); colorMenu = new KMPlayerPopupMenu (this, i18n ("Co&lors")); colorAction = popupMenu->addMenu (colorMenu); colorAction->setIcon(QIcon::fromTheme("format-fill-color")); /*QLabel * label = new QLabel (i18n ("Contrast:"), colorMenu); colorMenu->insertItem (label); m_contrastSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, colorMenu); colorMenu->insertItem (m_contrastSlider); label = new QLabel (i18n ("Brightness:"), colorMenu); colorMenu->insertItem (label); m_brightnessSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, colorMenu); colorMenu->insertItem (m_brightnessSlider); label = new QLabel (i18n ("Hue:"), colorMenu); colorMenu->insertItem (label); m_hueSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, colorMenu); colorMenu->insertItem (m_hueSlider); label = new QLabel (i18n ("Saturation:"), colorMenu); colorMenu->insertItem (label); m_saturationSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, colorMenu); colorMenu->insertItem (m_saturationSlider);*/ colorAction->setVisible (false); bookmarkMenu = new KMPlayerPopupMenu (this, i18n("&Bookmarks")); bookmarkAction = popupMenu->addMenu (bookmarkMenu); bookmarkAction->setVisible (false); languageMenu = new KMPlayerPopupMenu (this, i18n ("&Audio languages")); languageAction = popupMenu->addMenu (languageMenu); audioMenu = new KMPlayerPopupMenu (this, i18n ("&Audio languages")); subtitleMenu = new KMPlayerPopupMenu (this, i18n ("&Subtitles")); QAction *audioAction = languageMenu->addMenu (audioMenu); QAction *subtitleAction = languageMenu->addMenu (subtitleMenu); audioAction->setIcon(QIcon::fromTheme("audio-x-generic")); subtitleAction->setIcon(QIcon::fromTheme("view-list-text")); languageAction->setVisible (false); scaleLabelAction = new QWidgetAction (popupMenu); scaleLabelAction->setDefaultWidget (new QLabel (i18n ("Scale:"))); popupMenu->addAction (scaleLabelAction); scaleAction = new QWidgetAction (popupMenu); scale_slider = new QSlider; scale_slider->setOrientation (Qt::Horizontal); scale_slider->setMinimum (50); scale_slider->setMaximum (150); scale_slider->setPageStep (10); scale_slider->setSliderPosition (100); scaleAction->setDefaultWidget (scale_slider); popupMenu->addAction (scaleAction); configureAction = popupMenu->addAction(QIcon::fromTheme("configure"), i18n("&Configure KMPlayer...")); QPalette pal = palette (); pal.setColor(backgroundRole(), view->palette().color(QPalette::Background)); setPalette (pal); setAutoControls (true); connect (m_buttons [button_config], SIGNAL (clicked ()), this, SLOT (buttonClicked ())); connect (m_buttons [button_language], SIGNAL (clicked ()), this, SLOT (buttonClicked ())); connect (m_buttons [button_config], SIGNAL (mouseEntered ()), this, SLOT (buttonMouseEntered ())); connect (m_buttons [button_language], SIGNAL (mouseEntered ()), this, SLOT (buttonMouseEntered ())); connect (popupMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); connect (playerMenu, SIGNAL (mouseLeft ()), this, SLOT(menuMouseLeft ())); connect (zoomMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); connect (colorMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); connect (languageMenu, SIGNAL(mouseLeft ()), this, SLOT(menuMouseLeft())); connect (subtitleMenu, SIGNAL(mouseLeft ()), this, SLOT(menuMouseLeft())); connect (audioMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); } KDE_NO_EXPORT void ControlPanel::setPalette (const QPalette & pal) { QWidget::setPalette (pal); QColor c = palette ().color (foregroundRole ()); if (c == Qt::black) return; strncpy (xpm_fg_color, QString().sprintf(". c #%02x%02x%02x", c.red(), c.green(),c.blue()).toAscii().constData(), 31); xpm_fg_color[31] = 0; m_buttons[button_config]->setIcon(makeIcon(config_xpm)); m_buttons[button_playlist]->setIcon(makeIcon(playlist_xpm)); m_buttons[button_back]->setIcon(makeIcon(back_xpm)); m_buttons[button_play]->setIcon(makeIcon(play_xpm)); m_buttons[button_forward]->setIcon(makeIcon(forward_xpm)); m_buttons[button_stop]->setIcon(makeIcon(stop_xpm)); m_buttons[button_pause]->setIcon(makeIcon(pause_xpm)); m_buttons[button_record]->setIcon(makeIcon(record_xpm)); m_buttons[button_broadcast]->setIcon(makeIcon(broadcast_xpm)); m_buttons[button_language]->setIcon(makeIcon(language_xpm)); m_buttons[button_red]->setIcon(makeIcon(red_xpm)); m_buttons[button_green]->setIcon(makeIcon(green_xpm)); m_buttons[button_yellow]->setIcon(makeIcon(yellow_xpm)); m_buttons[button_blue]->setIcon(makeIcon(blue_xpm)); } KDE_NO_EXPORT void ControlPanel::timerEvent (QTimerEvent * e) { if (e->timerId () == m_popup_timer) { m_popup_timer = 0; if (m_button_monitored == button_config) { if (m_buttons [button_config]->testAttribute(Qt::WA_UnderMouse) && !popupMenu->isVisible ()) showPopupMenu (); } else if (m_buttons [button_language]->testAttribute(Qt::WA_UnderMouse) && !languageMenu->isVisible ()) { showLanguageMenu (); } } else if (e->timerId () == m_popdown_timer) { m_popdown_timer = 0; QPoint mpos = QCursor::pos(); #define HAS_MOUSE(menu) ((menu)->isVisible() && (menu)->rect().contains((menu)->mapFromGlobal(mpos))) if (popupMenu->isVisible () && !popupMenu->underMouse() && !HAS_MOUSE(playerMenu) && !HAS_MOUSE(zoomMenu) && !HAS_MOUSE(colorMenu) && !HAS_MOUSE(bookmarkMenu)) { if (!(bookmarkMenu->isVisible () && static_cast (bookmarkMenu) != QWidget::keyboardGrabber ())) { // not if user entered the bookmark sub menu or if I forgot one popupMenu->hide (); if (m_buttons [button_config]->isChecked ()) m_buttons [button_config]->toggle (); } } else if (languageMenu->isVisible () && !HAS_MOUSE(languageMenu) && !HAS_MOUSE(audioMenu) && !HAS_MOUSE(subtitleMenu)) { languageMenu->hide (); if (m_buttons [button_language]->isChecked ()) m_buttons [button_language]->toggle (); } #undef HAS_MOUSE } killTimer (e->timerId ()); } void ControlPanel::setAutoControls (bool b) { m_auto_controls = b; if (m_auto_controls) { for (int i = 0; i < (int) button_broadcast; i++) m_buttons [i]->show (); for (int i = button_broadcast; i < (int) button_last; i++) m_buttons [i]->hide (); showPositionSlider (false); m_volume->show (); if (m_buttons [button_broadcast]->isChecked ()) // still broadcasting m_buttons [button_broadcast]->show (); } else { // hide everything for (int i = 0; i < (int) button_last; i++) m_buttons [i]->hide (); m_posSlider->hide (); m_volume->hide (); } m_view->updateLayout (); } KDE_NO_EXPORT void ControlPanel::showPopupMenu () { popupMenu->exec (m_buttons [button_config]->mapToGlobal (QPoint (0, maximumSize ().height ()))); } KDE_NO_EXPORT void ControlPanel::showLanguageMenu () { languageMenu->exec (m_buttons [button_language]->mapToGlobal (QPoint (0, maximumSize ().height ()))); } void ControlPanel::showPositionSlider (bool show) { if (!m_auto_controls || show == m_posSlider->isVisible ()) return; setupPositionSlider (show); if (isVisible ()) m_view->updateLayout (); } KDE_NO_EXPORT void ControlPanel::setupPositionSlider (bool show) { int h = show ? button_height_with_slider : button_height_only_buttons; m_posSlider->setEnabled (false); m_posSlider->setValue (0); m_posSlider->setVisible (show); for (int i = 0; i < (int) button_last; i++) { m_buttons[i]->setMinimumSize (15 * dpi_scale, (h-1) * dpi_scale); m_buttons[i]->setMaximumHeight(h * dpi_scale); } setMaximumHeight((h + 6) * dpi_scale); } KDE_NO_EXPORT int ControlPanel::preferredHeight () { return dpi_scale * (m_posSlider->isVisible () ? button_height_with_slider + 8 : button_height_only_buttons + 2); } void ControlPanel::enableSeekButtons (bool enable) { if (!m_auto_controls) return; if (enable) { m_buttons[button_back]->show (); m_buttons[button_forward]->show (); } else { m_buttons[button_back]->hide (); m_buttons[button_forward]->hide (); } } void ControlPanel::enableRecordButtons (bool enable) { if (!m_auto_controls) return; if (enable) m_buttons[button_record]->show (); else m_buttons[button_record]->hide (); } void ControlPanel::enableFullscreenButton(bool enable) { m_buttons[button_playlist]->setIcon(makeIcon(enable ? normal_window_xpm : playlist_xpm)); } void ControlPanel::setPlaying (bool play) { if (play != m_buttons[button_play]->isChecked ()) m_buttons[button_play]->toggle (); m_posSlider->setEnabled (false); m_posSlider->setValue (0); if (!play) { showPositionSlider (false); enableSeekButtons (true); } } KDE_NO_EXPORT void ControlPanel::setRecording (bool record) { if (record != m_buttons[button_record]->isChecked ()) m_buttons[button_record]->toggle (); } KDE_NO_EXPORT void ControlPanel::setPlayingProgress (int pos, int len) { m_posSlider->setEnabled (false); m_progress_length = len; showPositionSlider (len > 0); if (m_progress_mode != progress_playing) { m_posSlider->setMaximum (m_progress_length); m_progress_mode = progress_playing; } if (pos < len && len > 0 && len != m_posSlider->maximum ()) m_posSlider->setMaximum (m_progress_length); else if (m_progress_length <= 0 && pos > 7 * m_posSlider->maximum ()/8) m_posSlider->setMaximum (m_posSlider->maximum() * 2); else if (m_posSlider->maximum() < pos) m_posSlider->setMaximum (int (1.4 * m_posSlider->maximum())); m_posSlider->setValue (pos); m_posSlider->setEnabled (true); } KDE_NO_EXPORT void ControlPanel::setLoadingProgress (int pos) { if (pos > 0 && pos < 100 && !m_posSlider->isVisible ()) showPositionSlider (true); else if (pos >= 100 && m_posSlider->isVisible ()) showPositionSlider (false); m_posSlider->setEnabled (false); if (m_progress_mode != progress_loading) { m_posSlider->setMaximum (100); m_progress_mode = progress_loading; } m_posSlider->setValue (pos); } KDE_NO_EXPORT void ControlPanel::buttonClicked () { if (m_popup_timer) { killTimer (m_popup_timer); m_popup_timer = 0; } m_popup_clicked = true; if (sender () == m_buttons [button_language]) showLanguageMenu (); else showPopupMenu (); } KDE_NO_EXPORT void ControlPanel::buttonMouseEntered () { if (!m_popup_timer) { if (sender () == m_buttons [button_config]) { if (!popupMenu->isVisible ()) { m_button_monitored = button_config; m_popup_clicked = false; m_popup_timer = startTimer (400); } } else if (!languageMenu->isVisible ()) { m_button_monitored = button_language; m_popup_clicked = false; m_popup_timer = startTimer (400); } } } KDE_NO_EXPORT void ControlPanel::menuMouseLeft () { if (!m_popdown_timer && !m_popup_clicked) m_popdown_timer = startTimer (400); } KDE_NO_EXPORT void ControlPanel::setLanguages (const QStringList & alang, const QStringList & slang) { int sz = (int) alang.size (); bool showbutton = (sz > 0); audioMenu->clear (); for (int i = 0; i < sz; i++) audioMenu->addAction (alang [i])->setCheckable(true); sz = (int) slang.size (); showbutton |= (sz > 0); subtitleMenu->clear (); for (int i = 0; i < sz; i++) subtitleMenu->addAction (slang [i])->setCheckable(true); if (showbutton) m_buttons [button_language]->show (); else m_buttons [button_language]->hide (); } KDE_NO_EXPORT void ControlPanel::actionToggled (QAction* act) { if (act->isChecked ()) return; int size = act->parentWidget()->actions().count(); for (int i = 0; i < size; i++) if (act->parentWidget()->actions().at(i)->isChecked ()) { act->parentWidget()->actions().at(i)->setChecked (false); break; } act->setChecked (true); } //----------------------------------------------------------------------------- #include "kmplayercontrolpanel.moc" diff --git a/src/kmplayerpartbase.cpp b/src/kmplayerpartbase.cpp index eaf6e3a..2c23069 100644 --- a/src/kmplayerpartbase.cpp +++ b/src/kmplayerpartbase.cpp @@ -1,1594 +1,1590 @@ /** * Copyright (C) 2002-2003 by Koos Vriezen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, * Boston, MA 02110-1301, USA. **/ #ifdef KDE_USE_FINAL #undef Always #endif #include "config-kmplayer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmplayerpartbase.h" #include "kmplayerview.h" #include "playmodel.h" #include "playlistview.h" #include "kmplayerprocess.h" #include "viewarea.h" #include "kmplayercontrolpanel.h" #include "kmplayerconfig.h" #include "kmplayer_smil.h" #include "mediaobject.h" #include "partadaptor.h" namespace KMPlayer { class KMPLAYER_NO_EXPORT BookmarkOwner : public KBookmarkOwner { public: BookmarkOwner (PartBase *); KDE_NO_CDTOR_EXPORT virtual ~BookmarkOwner () {} void openBookmark(const KBookmark &bm, Qt::MouseButtons mb, Qt::KeyboardModifiers km); QString currentTitle() const; QString currentURL() const; private: PartBase * m_player; }; } // namespace using namespace KMPlayer; KDE_NO_CDTOR_EXPORT BookmarkOwner::BookmarkOwner (PartBase * player) : m_player (player) {} KDE_NO_EXPORT void BookmarkOwner::openBookmark(const KBookmark &bm, Qt::MouseButtons, Qt::KeyboardModifiers) { if (!bm.isNull ()) m_player->openUrl (bm.url ()); } KDE_NO_EXPORT QString BookmarkOwner::currentTitle () const { return m_player->source ()->prettyName (); } KDE_NO_EXPORT QString BookmarkOwner::currentURL () const { return m_player->source ()->url ().url (); } //----------------------------------------------------------------------------- PartBase::PartBase (QWidget * wparent, QObject * parent, KSharedConfigPtr config) : KMediaPlayer::Player (wparent, "kde_kmplayer_part", parent), m_config (config), m_view (new View (wparent)), m_settings (new Settings (this, config)), m_media_manager (new MediaManager (this)), m_play_model (new PlayModel (this, KIconLoader::global ())), m_source (0L), m_bookmark_menu (0L), m_update_tree_timer (0), m_rec_timer (0), m_noresize (false), m_auto_controls (true), m_bPosSliderPressed (false), m_in_update_tree (false), m_update_tree_full (false) { m_sources ["urlsource"] = new URLSource (this); QString bmfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kmplayer/bookmarks.xml"); QString localbmfile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/bookmarks.xml"; if (localbmfile != bmfile) { bool bmfileCopied = QFile(bmfile).copy(localbmfile); kDebug() << "bookmarks.xml copied successfully?" << bmfileCopied; } m_bookmark_manager = KBookmarkManager::managerForFile (localbmfile, "kmplayer"); m_bookmark_owner = new BookmarkOwner (this); } void PartBase::showConfigDialog () { m_settings->show ("URLPage"); } KDE_NO_EXPORT void PartBase::showPlayListWindow () { // note, this is also the slot of application's view_playlist action, but // anyhow, actions don't work for the fullscreen out-of-the-box, so ... if (m_view->viewArea ()->isFullScreen ()) fullScreen (); else if (m_view->viewArea ()->isMinimalMode ()) ; //done by app: m_view->viewArea ()->minimalMode (); else m_view->toggleShowPlaylist (); } KDE_NO_EXPORT void PartBase::addBookMark (const QString & t, const QString & url) { KBookmarkGroup b = m_bookmark_manager->root (); b.addBookmark (t, KUrl (url), KIO::iconNameForUrl(url)); m_bookmark_manager->emitChanged (b); } void PartBase::init (KActionCollection * action_collection, const QString &objname, bool transparent) { KParts::Part::setWidget (m_view); m_view->init (action_collection, transparent); connect(m_settings, SIGNAL(configChanged()), this, SLOT(settingsChanged())); m_settings->readConfig (); m_settings->applyColorSetting (false); connect (m_view, SIGNAL(urlDropped(const QList&)), this, SLOT(openUrl(const QList&))); connectPlaylist (m_view->playList ()); connectInfoPanel (m_view->infoPanel ()); (void) new PartAdaptor (this); QDBusConnection::sessionBus().registerObject (objname, this); } void PartBase::connectPanel (ControlPanel * panel) { /*panel->contrastSlider ()->setValue (m_settings->contrast); panel->brightnessSlider ()->setValue (m_settings->brightness); panel->hueSlider ()->setValue (m_settings->hue); panel->saturationSlider ()->setValue (m_settings->saturation); panel->volumeBar ()->setValue (m_settings->volume);*/ connect (panel->button (ControlPanel::button_playlist), SIGNAL (clicked ()), this, SLOT (showPlayListWindow ())); connect (panel->button (ControlPanel::button_back), SIGNAL (clicked ()), this, SLOT (back ())); connect (panel->button (ControlPanel::button_play), SIGNAL (clicked ()), this, SLOT (play ())); connect (panel->button (ControlPanel::button_forward), SIGNAL (clicked ()), this, SLOT (forward ())); connect (panel->button (ControlPanel::button_pause), SIGNAL (clicked ()), this, SLOT (pause ())); connect (panel->button (ControlPanel::button_stop), SIGNAL (clicked ()), this, SLOT (stop ())); connect (panel->button (ControlPanel::button_record), SIGNAL (clicked()), this, SLOT (record())); connect (panel->volumeBar (), SIGNAL (volumeChanged (int)), this, SLOT (volumeChanged (int))); connect (panel->positionSlider (), SIGNAL (valueChanged (int)), this, SLOT (positionValueChanged (int))); connect (panel->positionSlider (), SIGNAL (sliderPressed()), this, SLOT (posSliderPressed())); connect (panel->positionSlider (), SIGNAL (sliderReleased()), this, SLOT (posSliderReleased())); connect (this, SIGNAL (positioned (int, int)), panel, SLOT (setPlayingProgress (int, int))); connect (this, SIGNAL (loading(int)), panel, SLOT(setLoadingProgress(int))); /*connect (panel->contrastSlider (), SIGNAL (valueChanged(int)), this, SLOT (contrastValueChanged(int))); connect (panel->brightnessSlider (), SIGNAL (valueChanged(int)), this, SLOT (brightnessValueChanged(int))); connect (panel->hueSlider (), SIGNAL (valueChanged(int)), this, SLOT (hueValueChanged(int))); connect (panel->saturationSlider (), SIGNAL (valueChanged(int)), this, SLOT (saturationValueChanged(int)));*/ connect (this, SIGNAL (languagesUpdated(const QStringList &, const QStringList &)), panel, SLOT (setLanguages (const QStringList &, const QStringList &))); connect (panel->audioMenu, SIGNAL (triggered (QAction*)), this, SLOT (audioSelected (QAction*))); connect (panel->subtitleMenu, SIGNAL (triggered (QAction*)), this, SLOT (subtitleSelected (QAction*))); connect (panel->playerMenu, SIGNAL (triggered (QAction*)), this, SLOT (slotPlayerMenu (QAction*))); connect (this, SIGNAL (panelActionToggled (QAction*)), panel, SLOT (actionToggled (QAction*))); connect (panel->fullscreenAction, SIGNAL (triggered (bool)), this, SLOT (fullScreen ())); connect (panel->configureAction, SIGNAL (triggered (bool)), this, SLOT (showConfigDialog ())); connect (panel->videoConsoleAction, SIGNAL (triggered (bool)), m_view, SLOT(toggleVideoConsoleWindow ())); connect (panel->playlistAction, SIGNAL (triggered (bool)), m_view, SLOT (toggleShowPlaylist ())); connect (this, SIGNAL (statusUpdated (const QString &)), panel->view (), SLOT (setStatusMessage (const QString &))); //connect (panel (), SIGNAL (clicked ()), m_settings, SLOT (show ())); } void PartBase::createBookmarkMenu(QMenu *owner, KActionCollection *ac) { m_bookmark_menu = new KBookmarkMenu (m_bookmark_manager, m_bookmark_owner, owner, ac); } void PartBase::connectPlaylist (PlayListView * playlist) { playlist->setModel (m_play_model); connect (m_play_model, SIGNAL (updating (const QModelIndex &)), playlist, SLOT(modelUpdating (const QModelIndex &))); connect (m_play_model, SIGNAL (updated (const QModelIndex&, const QModelIndex&, bool, bool)), playlist, SLOT(modelUpdated (const QModelIndex&, const QModelIndex&, bool, bool))); connect (playlist->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), playlist, SLOT(slotCurrentItemChanged(QModelIndex,QModelIndex))); connect (playlist, SIGNAL (addBookMark (const QString &, const QString &)), this, SLOT (addBookMark (const QString &, const QString &))); connect (playlist, SIGNAL (activated (const QModelIndex &)), this, SLOT (playListItemActivated (const QModelIndex &))); connect (playlist, SIGNAL (clicked (const QModelIndex&)), this, SLOT (playListItemClicked (const QModelIndex&))); connect (this, SIGNAL (treeChanged (int, NodePtr, NodePtr, bool, bool)), playlist->model (), SLOT (updateTree (int, NodePtr, NodePtr, bool, bool))); } void PartBase::connectInfoPanel (InfoWindow * infopanel) { connect (this, SIGNAL (infoUpdated (const QString &)), infopanel->view (), SLOT (setInfoMessage (const QString &))); } PartBase::~PartBase () { kDebug() << "PartBase::~PartBase"; m_view = (View*) 0; stopRecording (); stop (); if (m_source) m_source->deactivate (); delete m_media_manager; if (m_record_doc) m_record_doc->document ()->dispose (); delete m_settings; delete m_bookmark_menu; delete m_sources ["urlsource"]; //delete m_bookmark_manager; delete m_bookmark_owner; } KDE_NO_EXPORT void PartBase::showControls (bool show) { viewWidget ()->setControlPanelMode ( show ? View::CP_Show : View::CP_Hide); } QString PartBase::getStatus () { QString rval = "Waiting"; if (source() && source()->document()) { if (source()->document()->unfinished ()) rval = "Playable"; else if (source()->document()->state >= Node::state_deactivated) rval = "Complete"; } return rval; } QString PartBase::doEvaluate (const QString &) { return "undefined"; } void PartBase::settingsChanged () { if (!m_view) return; if (m_settings->showcnfbutton) m_view->controlPanel()->button (ControlPanel::button_config)->show(); else m_view->controlPanel()->button (ControlPanel::button_config)->hide(); m_view->controlPanel()->enableRecordButtons (m_settings->showrecordbutton); if (m_settings->showplaylistbutton) m_view->controlPanel()->button (ControlPanel::button_playlist)->show(); else m_view->controlPanel()->button (ControlPanel::button_playlist)->hide(); if (!m_settings->showbroadcastbutton) m_view->controlPanel ()->broadcastButton ()->hide (); keepMovieAspect (m_settings->sizeratio); m_settings->applyColorSetting (true); } KMediaPlayer::View* PartBase::view () { return m_view; } extern const char * strGeneralGroup; QString PartBase::processName (Mrl *mrl) { if (id_node_grab_document == mrl->id) return QString ("mplayer"); //FIXME // determine backend, start with temp_backends QString p = temp_backends [m_source->name()]; bool remember_backend = p.isEmpty (); MediaManager::ProcessInfoMap &pinfos = m_media_manager->processInfos (); if (p.isEmpty ()) { // next try to find mimetype match from kmplayerrc if (!mrl->mimetype.isEmpty ()) { KConfigGroup mime_cfg (m_config, mrl->mimetype); p = mime_cfg.readEntry ("player", QString ()); remember_backend = !(!p.isEmpty () && pinfos.contains (p) && pinfos [p]->supports (m_source->name ())); } } if (p.isEmpty ()) // try source match from kmplayerrc p = m_settings->backends [m_source->name()]; if (p.isEmpty ()) { // try source match from kmplayerrc by re-reading p = KConfigGroup(m_config, strGeneralGroup).readEntry(m_source->name(),QString()); } if (p.isEmpty () || !pinfos.contains (p) || !pinfos [p]->supports (m_source->name ())) { // finally find first supported player p.truncate (0); const MediaManager::ProcessInfoMap::const_iterator e = pinfos.constEnd(); for (MediaManager::ProcessInfoMap::const_iterator i = pinfos.constBegin(); i != e; ++i) if (i.value ()->supports (m_source->name ())) { p = QString (i.value ()->name); break; } } if (!p.isEmpty ()) { updatePlayerMenu (m_view->controlPanel (), p); if (remember_backend) m_settings->backends [m_source->name()] = p; else temp_backends [m_source->name()] = QString (); } return p; } void PartBase::processCreated (Process*) {} KDE_NO_EXPORT void PartBase::slotPlayerMenu (QAction* act) { Mrl *mrl = m_source->current (); bool playing = mrl && mrl->active (); const char * srcname = m_source->name (); QMenu *player_menu = m_view->controlPanel ()->playerMenu; MediaManager::ProcessInfoMap &pinfos = m_media_manager->processInfos (); const MediaManager::ProcessInfoMap::const_iterator e = pinfos.constEnd(); int id = 0; for (MediaManager::ProcessInfoMap::const_iterator i = pinfos.constBegin(); id < player_menu->actions().count() && i != e; ++i) { ProcessInfo *pinfo = i.value (); if (!pinfo->supports (srcname)) continue; QAction* menu = player_menu->actions().at (id); menu->setChecked (menu == act); if (menu == act) { if (strcmp (pinfo->name, "npp")) m_settings->backends [srcname] = pinfo->name; temp_backends [srcname] = pinfo->name; } id++; } if (playing) m_source->play (mrl); } void PartBase::updatePlayerMenu (ControlPanel *panel, const QString &backend) { if (!m_view) return; QMenu *menu = panel->playerMenu; menu->clear (); MediaManager::ProcessInfoMap &pinfos = m_media_manager->processInfos (); const MediaManager::ProcessInfoMap::const_iterator e = pinfos.constEnd(); for (MediaManager::ProcessInfoMap::const_iterator i = pinfos.constBegin(); i != e; ++i) { ProcessInfo *p = i.value (); if (p->supports (m_source ? m_source->name () : "urlsource")) { QAction* act = menu->addAction (p->label); act->setCheckable(true); if (backend == p->name) act->setChecked (true); } } } void PartBase::connectSource (Source * old_source, Source * source) { if (old_source) { disconnect (old_source, SIGNAL(endOfPlayItems ()), this, SLOT(stop ())); disconnect (old_source, SIGNAL (dimensionsChanged ()), this, SLOT (sourceHasChangedAspects ())); disconnect (old_source, SIGNAL (startPlaying ()), this, SLOT (slotPlayingStarted ())); disconnect (old_source, SIGNAL (stopPlaying ()), this, SLOT (slotPlayingStopped ())); } if (source) { connect (source, SIGNAL (endOfPlayItems ()), this, SLOT (stop ())); connect (source, SIGNAL (dimensionsChanged ()), this, SLOT (sourceHasChangedAspects ())); connect (source, SIGNAL (startPlaying ()), this, SLOT (slotPlayingStarted ())); connect (source, SIGNAL (stopPlaying ()), this, SLOT (slotPlayingStopped ())); } } void PartBase::setSource (Source * _source) { Source * old_source = m_source; if (m_source) { m_source->deactivate (); stop (); if (m_view) { m_view->reset (); emit infoUpdated (QString ()); } disconnect (this, SIGNAL (audioIsSelected (int)), m_source, SLOT (setAudioLang (int))); disconnect (this, SIGNAL (subtitleIsSelected (int)), m_source, SLOT (setSubtitle (int))); } if (m_view) { if (m_auto_controls) m_view->controlPanel ()->setAutoControls (m_auto_controls); m_view->controlPanel ()->enableRecordButtons (m_settings->showrecordbutton); if (!m_settings->showcnfbutton) m_view->controlPanel()->button(ControlPanel::button_config)->hide(); if (!m_settings->showplaylistbutton) m_view->controlPanel()->button(ControlPanel::button_playlist)->hide(); } m_source = _source; connectSource (old_source, m_source); connect (this, SIGNAL (audioIsSelected (int)), m_source, SLOT (setAudioLang (int))); connect (this, SIGNAL (subtitleIsSelected (int)), m_source, SLOT (setSubtitle (int))); m_source->init (); m_source->setIdentified (false); if (m_view) updatePlayerMenu (m_view->controlPanel ()); if (m_source && !m_source->avoidRedirects ()) QTimer::singleShot (0, m_source, SLOT (slotActivate ())); updateTree (true, true); emit sourceChanged (old_source, m_source); } KDE_NO_EXPORT void PartBase::changeURL (const QString & url) { emit urlChanged (url); } bool PartBase::isSeekable (void) const { return m_source ? m_source->isSeekable () : false; } bool PartBase::hasLength () const { return m_source ? m_source->hasLength () : false; } qlonglong PartBase::length () const { return m_source ? m_source->length () : 0; } bool PartBase::openUrl (const QUrl &url) { return openUrl(KUrl(url)); } bool PartBase::openUrl (const KUrl &url) { kDebug () << "PartBase::openUrl " << url.url() << url.isValid (); if (!m_view) return false; stop (); Source * src = (url.isEmpty () ? m_sources ["urlsource"] : (!url.protocol ().compare ("kmplayer") && m_sources.contains (url.host ()) ? m_sources [url.host ()] : m_sources ["urlsource"])); setSource (src); src->setSubURL (KUrl ()); src->setUrl (url.isLocalFile () ? url.toLocalFile() : url.url ()); if (src->avoidRedirects ()) src->activate (); return true; } bool PartBase::openUrl(const QList& urls) { if (urls.size () == 1) { openUrl(KUrl(urls[0].toString())); } else { openUrl (KUrl ()); NodePtr d = m_source->document (); if (d) for (int i = 0; i < urls.size (); i++) { const KUrl &url = urls [i]; d->appendChild (new GenericURL (d, url.isLocalFile() ? url.toLocalFile() : url.toString())); } } return true; } void PartBase::openUrl (const KUrl &u, const QString &t, const QString &srv) { kDebug() << u << " " << t << " " << srv; QDBusMessage msg = QDBusMessage::createMethodCall ( "org.kde.klauncher", "/KLauncher", "org.kde.KLauncher", "start_service_by_desktop_name"); QStringList urls; urls << u.url (); msg << "kfmclient" << urls << QStringList () << QString () << true; msg.setDelayedReply (false); QDBusConnection::sessionBus().send (msg); } bool PartBase::closeUrl () { stop (); if (m_view) m_view->reset (); return true; } bool PartBase::openFile () { return false; } void PartBase::keepMovieAspect (bool b) { if (m_view) m_view->setKeepSizeRatio (b); } void PartBase::timerEvent (QTimerEvent * e) { if (e->timerId () == m_update_tree_timer) { m_update_tree_timer = 0; updateTree (m_update_tree_full, true); } else if (e->timerId () == m_rec_timer) { m_rec_timer = 0; if (m_record_doc) openUrl(KUrl(convertNode (m_record_doc)->record_file)); } killTimer (e->timerId ()); } void PartBase::playingStarted () { kDebug () << "playingStarted " << this; if (m_view) { m_view->controlPanel ()->setPlaying (true); m_view->controlPanel ()->showPositionSlider (!!m_source->length ()); m_view->controlPanel ()->enableSeekButtons (m_source->isSeekable ()); m_view->playingStart (); //if (m_settings->autoadjustvolume && m_process) // m_process->volume(m_view->controlPanel()->volumeBar()->value(),true); } emit loading (100); } void PartBase::slotPlayingStarted () { playingStarted (); } void PartBase::playingStopped () { kDebug () << "playingStopped " << this; if (m_view) { m_view->controlPanel ()->setPlaying (false); m_view->playingStop (); m_view->reset (); } m_bPosSliderPressed = false; } void PartBase::slotPlayingStopped () { playingStarted (); } KDE_NO_EXPORT void PartBase::setPosition (int position, int length) { if (m_view && !m_bPosSliderPressed) { if (m_media_manager->processes ().size () > 1) emit positioned (0, 0); else emit positioned (position, length); } } void PartBase::setLoaded (int percentage) { emit loading (percentage); } qlonglong PartBase::position () const { return m_source ? 100 * m_source->position () : 0; } void PartBase::pause () { NodePtr doc = m_source ? m_source->document () : 0L; if (doc) { Mrl *mrl = NULL; NodePtrW cur = m_source->current (); if (cur) { mrl = cur->mrl (); if (mrl && Mrl::WindowMode == mrl->view_mode) mrl = NULL; } if (doc->state == Node::state_deferred) { doc->undefer (); if (cur && mrl && mrl->state == Node::state_deferred) mrl->undefer (); } else { doc->defer (); if (cur && mrl && mrl->unfinished ()) mrl->defer (); } } } void PartBase::back () { m_source->backward (); } void PartBase::forward () { m_source->forward (); } KDE_NO_EXPORT void PartBase::playListItemClicked (const QModelIndex& index) { if (!index.isValid ()) return; PlayListView *pv = qobject_cast (sender ()); if (pv->model ()->rowCount ()) { if (pv->isExpanded (index)) pv->setExpanded (index, false); else pv->setExpanded (index, true); } } KDE_NO_EXPORT void PartBase::playListItemActivated(const QModelIndex &index) { if (m_in_update_tree) return; if (m_view->editMode ()) return; PlayListView *pv = qobject_cast (sender ()); if (!pv->model ()->parent (index).isValid () && index.row ()) return; // handled by playListItemClicked PlayItem *vi = static_cast (index.internalPointer ()); TopPlayItem *ri = vi->rootItem (); if (vi->node) { QString src = ri->source; NodePtrW node = vi->node; //kDebug() << src << " " << vi->node->nodeName(); Source * source = src.isEmpty() ? m_source : m_sources[src.toAscii().constData()]; if (node->isPlayable () || id_node_playlist_item == node->id) { source->play (node->mrl ()); //may become !isPlayable by lazy loading if (node && !node->isPlayable ()) emit treeChanged (ri->id, node, 0, false, true); } // else if (vi->childCount ()) {handled by playListItemClicked } else if (vi->attribute) { if (vi->attribute->name () == Ids::attr_src || vi->attribute->name () == Ids::attr_href || vi->attribute->name () == Ids::attr_url || vi->attribute->name () == Ids::attr_value || vi->attribute->name () == "data") { QString src (vi->attribute->value ()); if (!src.isEmpty ()) { PlayItem *pi = vi->parent (); if (pi) { for (Node *e = pi->node.ptr (); e; e = e->parentNode ()) { Mrl * mrl = e->mrl (); if (mrl) src = KUrl (mrl->absolutePath (), src).url (); } KUrl url (src); if (url.isValid ()) openUrl (url); } } } } else emit treeChanged (ri->id, ri->node, 0L, false, false); if (m_view) m_view->viewArea ()->setFocus (); } void PartBase::updateTree (bool full, bool force) { if (force) { m_in_update_tree = true; if (m_update_tree_full) { if (m_source) emit treeChanged (0, m_source->root (), m_source->current (), true, false); } m_in_update_tree = false; if (m_update_tree_timer) { killTimer (m_update_tree_timer); m_update_tree_timer = 0; } } else if (!m_update_tree_timer) { m_update_tree_timer = startTimer (100); m_update_tree_full = full; } else m_update_tree_full |= full; } void PartBase::updateInfo (const QString & msg) { emit infoUpdated (msg); } void PartBase::updateStatus (const QString & msg) { emit statusUpdated (msg); } void PartBase::setLanguages (const QStringList & al, const QStringList & sl) { emit languagesUpdated (al, sl); } KDE_NO_EXPORT void PartBase::audioSelected (QAction* act) { emit panelActionToggled(act); int i = act->parentWidget()->actions().indexOf(act); if (i >= 0) emit audioIsSelected (i); } KDE_NO_EXPORT void PartBase::subtitleSelected (QAction* act) { emit panelActionToggled(act); int i = act->parentWidget()->actions().indexOf(act); if (i >= 0) emit subtitleIsSelected (i); } void PartBase::recorderPlaying () { stop (); m_view->controlPanel ()->setRecording (true); emit recording (true); } void PartBase::recorderStopped () { stopRecording (); if (m_view && m_rec_timer < 0 && m_record_doc) openUrl(KUrl(convertNode (m_record_doc)->record_file)); } void PartBase::stopRecording () { if (m_view) { m_view->controlPanel ()->setRecording (false); emit recording (false); if (m_record_doc && m_record_doc->active ()) { m_record_doc->deactivate (); if (m_rec_timer > 0) killTimer (m_rec_timer); m_rec_timer = 0; } } } bool PartBase::isRecording () { return m_record_doc && m_record_doc->active (); } void PartBase::record () { if (m_view) m_view->setCursor (QCursor (Qt::WaitCursor)); if (!m_view->controlPanel()->button(ControlPanel::button_record)->isChecked ()) { stopRecording (); } else { m_settings->show ("RecordPage"); m_view->controlPanel ()->setRecording (false); } if (m_view) m_view->setCursor (QCursor (Qt::ArrowCursor)); } void PartBase::record (const QString &src, const QString &f, const QString &rec, int auto_start) { if (m_record_doc) { if (m_record_doc->active ()) m_record_doc->reset (); m_record_doc->document ()->dispose (); } m_record_doc = new RecordDocument (src, f, rec, source ()); m_record_doc->activate (); if (auto_start > 0) m_rec_timer = startTimer (auto_start); else m_rec_timer = auto_start; } void PartBase::play () { if (!m_view) return; QPushButton *pb = ::qobject_cast (sender ()); if (pb && !pb->isChecked ()) { stop (); return; } if (m_update_tree_timer) { killTimer (m_update_tree_timer); m_update_tree_timer = 0; } if (!playing ()) { PlayItem *lvi = m_view->playList ()->selectedItem (); if (lvi) { TopPlayItem *ri = lvi->rootItem (); if (ri->id != 0) // make sure it's in the first tree lvi = 0L; } if (!lvi) { QModelIndex index = m_view->playList ()->model ()->index (0, 0); lvi = static_cast(index.internalPointer ()); if (!lvi->node) lvi = NULL; } if (lvi) { Mrl *mrl = NULL; for (Node * n = lvi->node.ptr (); n; n = n->parentNode ()) { if (n->isPlayable ()) { mrl = n->mrl (); break; } if (!mrl && n->mrl () && !n->mrl ()->src.isEmpty ()) mrl = n->mrl (); } if (mrl) m_source->play (mrl); } } else { m_source->play (NULL); } } bool PartBase::playing () const { return m_source && m_source->document ()->active (); } void PartBase::stop () { QPushButton * b = m_view ? m_view->controlPanel ()->button (ControlPanel::button_stop) : 0L; if (b) { if (!b->isChecked ()) b->toggle (); m_view->setCursor (QCursor (Qt::WaitCursor)); } if (m_source) m_source->reset (); MediaManager::ProcessInfoMap &pi = m_media_manager->processInfos (); const MediaManager::ProcessInfoMap::const_iterator ie = pi.constEnd(); for (MediaManager::ProcessInfoMap::const_iterator i = pi.constBegin(); i != ie; ++i) i.value ()->quitProcesses (); MediaManager::ProcessList &processes = m_media_manager->processes (); const MediaManager::ProcessList::const_iterator e = processes.constEnd(); for (MediaManager::ProcessList::const_iterator i = processes.constBegin(); i != e; ++i) (*i)->quit (); if (m_view) { m_view->setCursor (QCursor (Qt::ArrowCursor)); if (b->isChecked ()) b->toggle (); m_view->controlPanel ()->setPlaying (false); setLoaded (100); updateStatus (i18n ("Ready")); } playingStopped (); } void PartBase::seek (qlonglong msec) { if (m_media_manager->processes ().size () == 1) m_media_manager->processes ().first ()->seek (msec/100, true); } void PartBase::adjustVolume (int incdec) { if (m_media_manager->processes ().size () > 0) m_media_manager->processes ().first ()->volume (incdec, false); } void PartBase::increaseVolume () { /*if (m_view) m_view->controlPanel ()->volumeBar ()->setValue (m_view->controlPanel ()->volumeBar ()->value () + 2);*/ } void PartBase::decreaseVolume () { //if (m_view) // m_view->controlPanel ()->volumeBar ()->setValue (m_view->controlPanel ()->volumeBar ()->value () - 2); } KDE_NO_EXPORT void PartBase::posSliderPressed () { m_bPosSliderPressed=true; } KDE_NO_EXPORT void PartBase::posSliderReleased () { m_bPosSliderPressed=false; -#if (QT_VERSION < 0x030200) - const QSlider * posSlider = dynamic_cast (sender ()); -#else const QSlider * posSlider = ::qobject_cast (sender ()); -#endif if (m_media_manager->processes ().size () == 1) m_media_manager->processes ().first ()->seek (posSlider->value(), true); } KDE_NO_EXPORT void PartBase::volumeChanged (int val) { if (m_media_manager->processes ().size () > 0) { m_settings->volume = val; m_media_manager->processes ().first ()->volume (val, true); } } KDE_NO_EXPORT void PartBase::contrastValueChanged (int val) { if (m_media_manager->processes ().size () > 0) m_media_manager->processes ().first ()->contrast (val, true); } KDE_NO_EXPORT void PartBase::brightnessValueChanged (int val) { if (m_media_manager->processes ().size () > 0) m_media_manager->processes ().first ()->brightness (val, true); } KDE_NO_EXPORT void PartBase::hueValueChanged (int val) { if (m_media_manager->processes ().size () > 0) m_media_manager->processes ().first ()->hue (val, true); } KDE_NO_EXPORT void PartBase::saturationValueChanged (int val) { m_settings->saturation = val; if (m_media_manager->processes ().size () > 0) m_media_manager->processes ().first ()->saturation (val, true); } KDE_NO_EXPORT void PartBase::sourceHasChangedAspects () { emit sourceDimensionChanged (); } KDE_NO_EXPORT void PartBase::positionValueChanged (int pos) { QSlider * slider = ::qobject_cast (sender ()); if (m_media_manager->processes ().size () == 1 && slider && slider->isEnabled ()) m_media_manager->processes ().first ()->seek (pos, true); } KDE_NO_EXPORT void PartBase::fullScreen () { if (m_view) m_view->fullScreen (); } KDE_NO_EXPORT void PartBase::toggleFullScreen () { m_view->fullScreen (); } KDE_NO_EXPORT bool PartBase::isPlaying () { return playing (); } KAboutData* PartBase::createAboutData () { KMessageBox::error(0L, "createAboutData", "KMPlayer"); return 0; } //----------------------------------------------------------------------------- SourceDocument::SourceDocument (Source *s, const QString &url) : Document (url, s), m_source (s) {} void SourceDocument::message (MessageType msg, void *data) { switch (msg) { case MsgInfoString: { QString info (data ? *((QString *) data) : QString ()); m_source->player ()->updateInfo (info); return; } case MsgAccessKey: for (Connection *c = m_KeyListeners.first(); c; c = m_KeyListeners.next ()) if (c->payload && c->connecter) { KeyLoad *load = (KeyLoad *) c->payload; if (load->key == (int) (long) data) post (c->connecter, new Posting (this, MsgAccessKey)); } return; default: break; } Document::message (msg, data); } void *SourceDocument::role (RoleType msg, void *data) { switch (msg) { case RoleMediaManager: return m_source->player ()->mediaManager (); case RoleChildDisplay: { PartBase *p = m_source->player (); if (p->view ()) return p->viewWidget ()->viewArea ()->getSurface ((Mrl *) data); return NULL; } case RoleReceivers: switch ((MessageType) (long) data) { case MsgAccessKey: return &m_KeyListeners; case MsgSurfaceUpdate: { PartBase *p = m_source->player (); if (p->view ()) return p->viewWidget ()->viewArea ()->updaters (); } // fall through default: break; } // fall through default: break; } return Document::role (msg, data); } Source::Source (const QString&, PartBase * player, const char * n) : QObject (player), m_name (n), m_player (player), m_identified (false), m_auto_play (true), m_avoid_redirects (false), m_frequency (0), m_xvport (0), m_xvencoding (-1), m_doc_timer (0) { init (); } Source::~Source () { if (m_document) m_document->document ()->dispose (); m_document = 0L; } void Source::init () { //setDimensions (320, 240); m_width = 0; m_height = 0; m_aspect = 0.0; m_length = 0; m_audio_id = -1; m_subtitle_id = -1; m_position = 0; setLength (m_document, 0); m_recordcmd.truncate (0); } KDE_NO_EXPORT void Source::setLanguages (LangInfoPtr audio, LangInfoPtr sub) { m_audio_infos = audio; m_subtitle_infos = sub; QStringList alst; QStringList slst; for (LangInfoPtr li = audio; li; li = li->next) alst.push_back (li->name); for (LangInfoPtr li = sub; li; li = li->next) slst.push_back (li->name); m_player->setLanguages (alst, slst); } void Source::setDimensions (NodePtr node, int w, int h) { Mrl *mrl = node ? node->mrl () : 0L; if (mrl) { float a = h > 0 ? 1.0 * w / h : 0.0; mrl->size = SSize (w, h); mrl->aspect = a; bool ev = (w > 0 && h > 0) || (h == 0 && m_height > 0) || (w == 0 && m_width > 0); if (Mrl::SingleMode == mrl->view_mode) { m_width = w; m_height = h; } if (Mrl::WindowMode == mrl->view_mode || m_aspect < 0.001) setAspect (node, h > 0 ? 1.0 * w / h : 0.0); //kDebug () << "setDimensions " << w << "x" << h << " a:" << m_aspect; else if (ev) emit dimensionsChanged (); } } void Source::setAspect (NodePtr node, float a) { //kDebug () << "setAspect " << a; Mrl *mrl = node ? node->mrl () : 0L; bool changed = false; if (mrl && mrl->media_info && mrl->media_info->media && MediaManager::AudioVideo == mrl->media_info->type) { static_cast (mrl->media_info->media)->viewer ()->setAspect(a); if (mrl->view_mode == Mrl::WindowMode) changed |= (fabs (mrl->aspect - a) > 0.001); mrl->aspect = a; } if (!mrl || mrl->view_mode == Mrl::SingleMode) { changed |= (fabs (m_aspect - a) > 0.001); m_aspect = a; if (changed && m_player->view ()) m_player->viewWidget ()->viewArea ()->resizeEvent (NULL); } else { mrl->message (MsgSurfaceBoundsUpdate); } if (changed) emit dimensionsChanged (); } void Source::setLength (NodePtr, int len) { m_length = len; m_player->setPosition (m_position, m_length); } KDE_NO_EXPORT void Source::setPosition (int pos) { m_position = pos; m_player->setPosition (pos, m_length); } KDE_NO_EXPORT void Source::setLoading (int percentage) { m_player->setLoaded (percentage); } /* static void printTree (NodePtr root, QString off=QString()) { if (!root) { kDebug() << off << "[null]"; return; } kDebug() << off << root->nodeName() << " " << (Element*)root << (root->isPlayable() ? root->mrl ()->src : QString ("-")); off += QString (" "); for (NodePtr e = root->firstChild(); e; e = e->nextSibling()) printTree(e, off); }*/ void Source::setUrl (const QString &url) { kDebug() << url; m_url = KUrl (url); if (m_document && !m_document->hasChildNodes () && (m_document->mrl()->src.isEmpty () || m_document->mrl()->src == url)) // special case, mime is set first by plugin FIXME v m_document->mrl()->src = url; else { if (m_document) m_document->document ()->dispose (); m_document = new SourceDocument (this, url); } if (m_player->source () == this) m_player->updateTree (); QTimer::singleShot (0, this, SLOT(changedUrl ())); } void Source::changedUrl() { emit titleChanged (this->prettyName ()); } void Source::setTitle (const QString & title) { emit titleChanged (title); } KDE_NO_EXPORT void Source::setAudioLang (int id) { LangInfoPtr li = m_audio_infos; for (; id > 0 && li; li = li->next) id--; m_audio_id = li ? li->id : -1; if (m_player->view () && m_player->mediaManager ()->processes ().size ()) m_player->mediaManager ()->processes ().first ()->setAudioLang (m_audio_id); } KDE_NO_EXPORT void Source::setSubtitle (int id) { LangInfoPtr li = m_subtitle_infos; for (; id > 0 && li; li = li->next) id--; m_subtitle_id = li ? li->id : -1; if (m_player->view () && m_player->mediaManager ()->processes ().size ()) m_player->mediaManager ()->processes ().first ()->setSubtitle (m_subtitle_id); } void Source::reset () { if (m_document) { kDebug() << "Source::reset " << name () << endl; NodePtr doc = m_document; // avoid recursive calls m_document = NULL; doc->reset (); m_document = doc; m_player->updateTree (); } init (); } void Source::play (Mrl *mrl) { if (!mrl) mrl = document ()->mrl (); NodePtrW guarded = mrl; blockSignals (true); //endOfPlayItems, but what is hyperspace? document ()->reset (); blockSignals (false); mrl = guarded ? guarded->mrl () : m_document->mrl (); if (!mrl) return; m_width = m_height = 0; m_player->changeURL (mrl->src); for (Node *p = mrl->parentNode(); p; p = p->parentNode()) p->state = Element::state_activated; mrl->activate (); m_width = mrl->size.width; m_height = mrl->size.height; m_aspect = mrl->aspect; //kDebug () << "Source::playCurrent " << (m_current ? m_current->nodeName():" doc act:") << (m_document && !m_document->active ()) << " cur:" << (!m_current) << " cur act:" << (m_current && !m_current->active ()); m_player->updateTree (); emit dimensionsChanged (); } bool Source::authoriseUrl (const QString &) { return true; } void Source::setTimeout (int ms) { //kDebug () << "Source::setTimeout " << ms; if (m_doc_timer) killTimer (m_doc_timer); m_doc_timer = ms > -1 ? startTimer (ms) : 0; } void Source::timerEvent (QTimerEvent * e) { if (e->timerId () == m_doc_timer && m_document && m_document->active ()) m_document->document ()->timer (); // will call setTimeout() else killTimer (e->timerId ()); } void Source::setCurrent (Mrl *mrl) { m_current = mrl; m_width = mrl->size.width; m_height = mrl->size.height; m_aspect = mrl->aspect; } void Source::stateElementChanged (Node *elm, Node::State os, Node::State ns) { //kDebug() << "Source::stateElementChanged " << elm->nodeName () << " state:" << (int) elm->state << " cur isPlayable:" << (m_current && m_current->isPlayable ()) << " elm==linkNode:" << (m_current && elm == m_current->mrl ()->linkNode ()) << endl; if (ns == Node::state_activated && elm->mrl ()) { if (Mrl::WindowMode != elm->mrl ()->view_mode && (!elm->parentNode () || !elm->parentNode ()->mrl () || Mrl::WindowMode != elm->parentNode ()->mrl ()->view_mode)) setCurrent (elm->mrl ()); if (m_current.ptr () == elm) emit startPlaying (); } else if (ns == Node::state_deactivated) { if (elm == m_document) { NodePtrW guard = elm; emit endOfPlayItems (); // played all items FIXME on jumps if (!guard) return; } else if (m_current.ptr () == elm) { emit stopPlaying (); } } if (elm->role (RolePlaylist)) { if (ns == Node::state_activated || ns == Node::state_deactivated) m_player->updateTree (); else if (ns == Node::state_began || os == Node::state_began) m_player->updateTree (false); } } void Source::bitRates (int & preferred, int & maximal) { preferred = 1024 * m_player->settings ()->prefbitrate; maximal= 1024 * m_player->settings ()->maxbitrate; } void Source::openUrl (const KUrl &url, const QString &t, const QString &srv) { m_player->openUrl (url, t, srv); } void Source::enableRepaintUpdaters (bool enable, unsigned int off_time) { if (m_player->view ()) m_player->viewWidget ()->viewArea()->enableUpdaters (enable, off_time); } void Source::insertURL (NodePtr node, const QString & mrl, const QString & title) { if (!node || !node->mrl ()) // this should always be false return; QString cur_url = node->mrl ()->absolutePath (); KUrl url (cur_url, mrl); QString urlstr = QUrl::fromPercentEncoding (url.url ().toUtf8 ()); kDebug() << cur_url << " " << urlstr; if (!url.isValid ()) kError () << "try to append non-valid url" << endl; else if (QUrl::fromPercentEncoding (cur_url.toUtf8 ()) == urlstr) kError () << "try to append url to itself" << endl; else { int depth = 0; // cache this? for (Node *e = node; e->parentNode (); e = e->parentNode ()) ++depth; if (depth < 40) { node->appendChild (new GenericURL (m_document, urlstr, title.isEmpty() ? QUrl::fromPercentEncoding (mrl.toUtf8 ()) : title)); m_player->updateTree (); } else kError () << "insertURL exceeds depth limit" << endl; } } void Source::backward () { Node *back = m_current ? m_current.ptr () : m_document.ptr (); while (back && back != m_document.ptr ()) { if (back->previousSibling ()) { back = back->previousSibling (); while (!back->isPlayable () && back->lastChild ()) back = back->lastChild (); if (back->isPlayable () && !back->active ()) { play (back->mrl ()); break; } } else { back = back->parentNode(); } } } void Source::forward () { if (m_current) m_current->finish (); if (m_document && !m_document->active ()) play (m_document->mrl ()); } void Source::setDocument (KMPlayer::NodePtr doc, KMPlayer::NodePtr cur) { if (m_document) m_document->document()->dispose (); m_document = doc; setCurrent (cur->mrl ()); //kDebug () << "setDocument: " << m_document->outerXML (); } NodePtr Source::document () { if (!m_document) m_document = new SourceDocument (this, QString ()); return m_document; } NodePtr Source::root () { return document (); } bool Source::processOutput (const QString &) { return false; } QString Source::filterOptions () { Settings* m_settings = m_player->settings (); QString PPargs (""); if (m_settings->postprocessing) { if (m_settings->pp_default) PPargs = "-vf pp=de"; else if (m_settings->pp_fast) PPargs = "-vf pp=fa"; else if (m_settings->pp_custom) { PPargs = "-vf pp="; if (m_settings->pp_custom_hz) { PPargs += "hb"; if (m_settings->pp_custom_hz_aq && \ m_settings->pp_custom_hz_ch) PPargs += ":ac"; else if (m_settings->pp_custom_hz_aq) PPargs += ":a"; else if (m_settings->pp_custom_hz_ch) PPargs += ":c"; PPargs += '/'; } if (m_settings->pp_custom_vt) { PPargs += "vb"; if (m_settings->pp_custom_vt_aq && \ m_settings->pp_custom_vt_ch) PPargs += ":ac"; else if (m_settings->pp_custom_vt_aq) PPargs += ":a"; else if (m_settings->pp_custom_vt_ch) PPargs += ":c"; PPargs += '/'; } if (m_settings->pp_custom_dr) { PPargs += "dr"; if (m_settings->pp_custom_dr_aq && \ m_settings->pp_custom_dr_ch) PPargs += ":ac"; else if (m_settings->pp_custom_dr_aq) PPargs += ":a"; else if (m_settings->pp_custom_dr_ch) PPargs += ":c"; PPargs += '/'; } if (m_settings->pp_custom_al) { PPargs += "al"; if (m_settings->pp_custom_al_f) PPargs += ":f"; PPargs += '/'; } if (m_settings->pp_custom_tn) { PPargs += "tn"; /*if (1 <= m_settings->pp_custom_tn_s <= 3){ PPargs += ":"; PPargs += m_settings->pp_custom_tn_s; }*/ //disabled 'cos this is wrong PPargs += '/'; } if (m_settings->pp_lin_blend_int) { PPargs += "lb"; PPargs += '/'; } if (m_settings->pp_lin_int) { PPargs += "li"; PPargs += '/'; } if (m_settings->pp_cub_int) { PPargs += "ci"; PPargs += '/'; } if (m_settings->pp_med_int) { PPargs += "md"; PPargs += '/'; } if (m_settings->pp_ffmpeg_int) { PPargs += "fd"; PPargs += '/'; } } if (PPargs.endsWith("/")) PPargs.truncate(PPargs.size ()-1); } return PPargs; } bool Source::hasLength () { return true; } bool Source::isSeekable () { return true; } void Source::setIdentified (bool b) { //kDebug () << "Source::setIdentified " << m_identified << b; m_identified = b; if (!b) { m_audio_infos = NULL; m_subtitle_infos = NULL; } } QString Source::plugin (const QString &mime) const { return KConfigGroup (m_player->config (), mime).readEntry ("plugin", QString ()); } QString Source::prettyName () { return i18n ("Unknown"); } void Source::slotActivate () { activate (); } //----------------------------------------------------------------------------- URLSource::URLSource (PartBase * player, const KUrl & url) : Source (i18n ("URL"), player, "urlsource"), activated (false) { setUrl (url.url ()); //kDebug () << "URLSource::URLSource"; } URLSource::~URLSource () { //kDebug () << "URLSource::~URLSource"; } void URLSource::init () { Source::init (); } void URLSource::dimensions (int & w, int & h) { if (!m_player->mayResize () && m_player->view ()) { w = static_cast (m_player->view ())->viewArea ()->width (); h = static_cast (m_player->view ())->viewArea ()->height (); } else { Source::dimensions (w, h); } } bool URLSource::hasLength () { return !!length (); } KDE_NO_EXPORT void URLSource::activate () { if (activated) return; activated = true; if (url ().isEmpty () && (!m_document || !m_document->hasChildNodes ())) { m_player->updateTree (); return; } if (m_auto_play) play (NULL); } void URLSource::reset () { Source::reset (); } void URLSource::forward () { Source::forward (); } void URLSource::backward () { Source::backward (); } void URLSource::play (Mrl *mrl) { Source::play (mrl); } void URLSource::deactivate () { if (!activated) return; activated = false; reset (); if (m_document) { m_document->document ()->dispose (); m_document = NULL; } if (m_player->view ()) m_player->viewWidget ()->viewArea ()->getSurface (NULL); } QString URLSource::prettyName () { if (m_url.isEmpty ()) return i18n ("URL"); if (m_url.url ().size () > 50) { QString newurl; if (!m_url.isLocalFile ()) { newurl = m_url.protocol () + QString ("://"); if (m_url.hasHost ()) newurl += m_url.host (); if (m_url.port () != -1) newurl += QString (":%1").arg (m_url.port ()); } QString file = m_url.fileName (); int len = newurl.size () + file.size (); KUrl path = KUrl (m_url.directory ()); bool modified = false; while (path.url ().size () + len > 50 && path != path.upUrl ()) { path = path.upUrl (); modified = true; } QString dir = path.directory (); if (!dir.endsWith (QString ("/"))) dir += '/'; if (modified) dir += QString (".../"); newurl += dir + file; return i18n ("URL - ") + newurl; } if (m_url.isLocalFile()) return i18n ("URL - ") + m_url.toLocalFile(); return i18n ("URL - ") + m_url.prettyUrl (); } bool URLSource::authoriseUrl (const QString &url) { KUrl base = document ()->mrl ()->src; if (base != url) { KUrl dest (url); // check if some remote playlist tries to open something local, but // do ignore unknown protocols because there are so many and we only // want to cache local ones. if ( #if 0 !KProtocolInfo::protocolClass (dest.protocol ()).isEmpty () && #else dest.isLocalFile () && #endif !KUrlAuthorized::authorizeUrlAction ("redirect", base, dest)) { kWarning () << "requestPlayURL from document " << base << " to play " << dest << " is not allowed"; return false; } } return Source::authoriseUrl (url); } void URLSource::setUrl (const QString &url) { Source::setUrl (url); Mrl *mrl = document ()->mrl (); if (!url.isEmpty () && m_url.isLocalFile () && mrl->mimetype.isEmpty ()) { KMimeType::Ptr mimeptr = KMimeType::findByUrl (m_url); if (mimeptr) mrl->mimetype = mimeptr->name (); } } //----------------------------------------------------------------------------- #include "kmplayerpartbase.moc" diff --git a/src/kmplayerview.cpp b/src/kmplayerview.cpp index 265b1de..588b326 100644 --- a/src/kmplayerview.cpp +++ b/src/kmplayerview.cpp @@ -1,592 +1,590 @@ /** * Copyright (C) 2002-2003 by Koos Vriezen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, * Boston, MA 02110-1301, USA. **/ #include #include #include "config-kmplayer.h" // include files for Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmplayerview.h" #include "kmplayercontrolpanel.h" #include "playlistview.h" #include "viewarea.h" #include /* mouse invisible: define the time (in 1/1000 seconds) before mouse goes invisible */ using namespace KMPlayer; //------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT PictureWidget::PictureWidget (QWidget * parent, View * view) : QWidget (parent), m_view (view) { setAutoFillBackground (true); } KDE_NO_EXPORT void PictureWidget::mousePressEvent (QMouseEvent *) { m_view->emitPictureClicked (); } KDE_NO_EXPORT void PictureWidget::mouseMoveEvent (QMouseEvent *e) { if (e->buttons () == Qt::NoButton) m_view->mouseMoved (e->x (), e->y ()); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT TextEdit::TextEdit (QWidget * parent, View * view) : QTextEdit (parent), m_view (view) { -#if QT_VERSION > 0x040399 setAttribute (Qt::WA_NativeWindow); setAttribute(Qt::WA_DontCreateNativeAncestors); -#endif setReadOnly (true); QPalette p=palette(); p.setColor (QPalette::Active, QPalette::Base, QColor (Qt::black)); p.setColor (QPalette::Active, QPalette::Foreground, (QColor (0xB2, 0xB2, 0xB2))); setPalette (p); } KDE_NO_EXPORT void TextEdit::contextMenuEvent (QContextMenuEvent * e) { m_view->controlPanel ()->popupMenu->exec (e->globalPos ()); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT InfoWindow::InfoWindow (QWidget *, View * view) : m_view (view) { setReadOnly (true); //setLinkUnderline (false); } KDE_NO_EXPORT void InfoWindow::contextMenuEvent (QContextMenuEvent * e) { m_view->controlPanel ()->popupMenu->exec (e->globalPos ()); } //----------------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT View::View (QWidget *parent) : KMediaPlayer::View (parent), m_control_panel (0L), m_status_bar (0L), m_controlpanel_mode (CP_Show), m_old_controlpanel_mode (CP_Show), m_statusbar_mode (SB_Hide), controlbar_timer (0), infopanel_timer (0), m_restore_state_timer(0), m_powerManagerStopSleep( -1 ), m_keepsizeratio (false), m_playing (false), m_tmplog_needs_eol (false), m_revert_fullscreen (false), m_no_info (false), m_edit_mode (false) { setAttribute (Qt::WA_NoSystemBackground, true); setAutoFillBackground (false); setAcceptDrops(true); } KDE_NO_EXPORT void View::dropEvent (QDropEvent * de) { QList uris = de->mimeData()->urls(); if (uris.isEmpty() || !uris[0].isValid()) { QString text = de->mimeData()->text(); if (!text.isEmpty()) uris.push_back(QUrl::fromUserInput(text)); } if (uris.size () > 0) { //m_widgetstack->currentWidget ()->setFocus (); emit urlDropped (uris); de->accept (); } } KDE_NO_EXPORT void View::dragEnterEvent (QDragEnterEvent* dee) { if (m_playlist->isDragValid (dee)) dee->accept (); } void View::initDock (QWidget *central) { m_dockarea = new QMainWindow; m_dockarea->setDockNestingEnabled(true); m_dockarea->setCentralWidget (central); central->setVisible (true); m_dock_playlist = new QDockWidget (i18n ("Playlist")); if (central != m_playlist) m_dock_playlist->setWidget (m_playlist); m_dock_playlist->setObjectName ("playlist"); m_dock_infopanel = new QDockWidget (i18n ("Information")); if (central != m_infopanel) m_dock_infopanel->setWidget (m_infopanel); m_dock_infopanel->setObjectName ("infopanel"); m_dock_playlist->hide (); m_dock_infopanel->hide (); m_dockarea->addDockWidget (Qt::BottomDockWidgetArea, m_dock_infopanel); m_dockarea->addDockWidget (Qt::LeftDockWidgetArea, m_dock_playlist); layout ()->addWidget (m_dockarea); m_dockarea->setWindowFlags (Qt::SubWindow); m_dockarea->show (); m_view_area->resizeEvent (0L); } KDE_NO_EXPORT void View::init (KActionCollection *action_collection, bool transparent) { QVBoxLayout * viewbox = new QVBoxLayout; viewbox->setContentsMargins (0, 0, 0, 0); setLayout (viewbox); m_view_area = new ViewArea (NULL, this, !transparent); m_playlist = new PlayListView (NULL, this, action_collection); m_picture = new PictureWidget (m_view_area, this); m_picture->hide (); m_control_panel = new ControlPanel (m_view_area, this); m_control_panel->setMaximumHeight(controlPanel ()->maximumSize ().height ()); m_status_bar = new StatusBar (m_view_area); m_status_bar->clearMessage(); m_status_bar->setAutoFillBackground (true); QSize sbsize = m_status_bar->sizeHint (); m_status_bar->hide (); m_status_bar->setMaximumHeight(sbsize.height ()); setVideoWidget (m_view_area); m_multiedit = new TextEdit (m_view_area, this); QFont fnt = QFontDatabase::systemFont(QFontDatabase::FixedFont); m_multiedit->setFont (fnt); m_multiedit->hide (); m_infopanel = new InfoWindow (NULL, this); connect (m_control_panel->scale_slider, SIGNAL (valueChanged (int)), m_view_area, SLOT (scale (int))); setFocusPolicy (Qt::ClickFocus); setAcceptDrops (true); } KDE_NO_CDTOR_EXPORT View::~View () { if (m_view_area->parent () != this) delete m_view_area; } KDE_NO_EXPORT void View::setEraseColor (const QColor & /*color*/) { /*KMediaPlayer::View::setEraseColor (color); if (statusBar ()) { statusBar ()->setEraseColor (color); controlPanel ()->setEraseColor (color); }*/ } void View::setInfoMessage (const QString & msg) { bool ismain = m_dockarea->centralWidget () == m_infopanel; if (msg.isEmpty ()) { if (!ismain && !m_edit_mode && !infopanel_timer) infopanel_timer = startTimer (0); m_infopanel->clear (); } else if (ismain || !m_no_info) { if (!ismain && !m_edit_mode && !m_dock_infopanel->isVisible ()) m_dock_infopanel->show (); if (m_edit_mode) m_infopanel->setPlainText (msg); else m_infopanel->setHtml (msg); } } void View::setStatusMessage (const QString & msg) { if (m_statusbar_mode != SB_Hide) m_status_bar->showMessage(msg); } void View::toggleShowPlaylist () { if (m_controlpanel_mode == CP_Only) return; if (m_dock_playlist->isVisible ()) m_dock_playlist->hide (); else m_dock_playlist->show(); /*if (m_dock_playlist->mayBeShow ()) { if (m_dock_playlist->isDockBackPossible ()) m_dock_playlist->dockBack (); else { bool horz = true; QStyle *style = m_playlist->style (); int h = style->pixelMetric (QStyle::PM_ScrollBarExtent, NULL, m_playlist); h += style->pixelMetric (QStyle::PM_DockWidgetFrameWidth, NULL, m_playlist); h +=style->pixelMetric (QStyle::PM_DockWidgetHandleExtent, NULL, m_playlist); for (Q3ListViewItem *i=m_playlist->firstChild();i;i=i->itemBelow()) { h += i->height (); if (h > int (0.25 * height ())) { horz = false; break; } } int perc = 30; if (horz && 100 * h / height () < perc) perc = 100 * h / height (); m_dock_playlist->manualDock (m_dock_video, horz ? K3DockWidget::DockTop : K3DockWidget::DockLeft, perc); } } else m_dock_playlist->undock ();*/ } void View::setViewOnly () { m_dock_playlist->hide (); m_dock_infopanel->hide (); } void View::setEditMode (TopPlayItem *ri, bool enable) { m_edit_mode = enable; m_infopanel->setReadOnly (!m_edit_mode); if (m_edit_mode && !m_dock_infopanel->isVisible ()) m_dock_infopanel->show (); //if (m_edit_mode && m_dock_infopanel->mayBeShow ()) // m_dock_infopanel->manualDock(m_dock_video,K3DockWidget::DockBottom,50); m_playlist->showAllNodes (ri, m_edit_mode); } #ifndef KMPLAYER_WITH_CAIRO bool View::setPicture (const QString & path) { if (path.isEmpty ()) m_image = QImage (); else { m_image = QImage (path); if (m_image.isNull ()) kDebug() << "View::setPicture failed " << path; else if (m_image.depth () < 24) m_image = m_image.convertToFormat (QImage::Format_RGB32); } m_picture->setVisible (!m_image.isNull ()); if (m_image.isNull ()) { m_view_area->setVideoWidgetVisible (true); } else { QPalette palette = m_picture->palette (); palette.setColor (m_picture->backgroundRole(), viewArea()->palette ().color (backgroundRole ())); palette.setBrush (m_picture->backgroundRole(), QBrush (m_image)); m_picture->setPalette (palette); m_view_area->setVideoWidgetVisible (false); controlPanel ()->raise (); setControlPanelMode (CP_AutoHide); } return !m_image.isNull (); } #endif void View::toggleVideoConsoleWindow () { if (m_multiedit->isVisible ()) { m_multiedit->hide (); m_view_area->setVideoWidgetVisible (true); m_control_panel->videoConsoleAction->setIcon(QIcon::fromTheme(("konsole"))); m_control_panel->videoConsoleAction->setText (i18n ("Con&sole")); delayedShowButtons (false); } else { m_control_panel->videoConsoleAction->setIcon(QIcon::fromTheme("video")); m_control_panel->videoConsoleAction->setText (i18n ("V&ideo")); m_multiedit->show (); m_multiedit->raise (); m_view_area->setVideoWidgetVisible (false); addText (QString (""), false); if (m_controlpanel_mode == CP_AutoHide && m_playing) m_control_panel->show(); } updateLayout (); emit windowVideoConsoleToggled (m_multiedit->isVisible ()); } void View::setControlPanelMode (ControlPanelMode m) { if (controlbar_timer) { killTimer (controlbar_timer); controlbar_timer = 0L; } m_old_controlpanel_mode = m_controlpanel_mode = m; if (m_playing && isFullScreen()) m_controlpanel_mode = CP_AutoHide; if ((m_controlpanel_mode == CP_Show || m_controlpanel_mode == CP_Only) && !m_control_panel->isVisible ()) { m_control_panel->show (); } else if (m_controlpanel_mode == CP_AutoHide) { if (!m_image.isNull () || (m_playing && !m_multiedit->isVisible ())) delayedShowButtons (false); else if (!m_control_panel->isVisible ()) { m_control_panel->show (); } } else if (m_controlpanel_mode == CP_Hide) { bool vis = m_control_panel->isVisible(); m_control_panel->hide (); if (vis) m_view_area->resizeEvent (0L); } m_view_area->resizeEvent (0L); } void View::setStatusBarMode (StatusBarMode m) { m_statusbar_mode = m; m_status_bar->setVisible (m != SB_Hide); m_view_area->resizeEvent (0L); } KDE_NO_EXPORT void View::delayedShowButtons (bool show) { if ((show && m_control_panel->isVisible ()) || (!show && !m_control_panel->isVisible ())) { if (controlbar_timer) { killTimer (controlbar_timer); controlbar_timer = 0; } if (!show) m_control_panel->hide (); // for initial race } else if (m_controlpanel_mode == CP_AutoHide && (m_playing || !m_image.isNull ()) && !m_multiedit->isVisible () && !controlbar_timer) { controlbar_timer = startTimer (500); } } KDE_NO_EXPORT void View::mouseMoved (int, int y) { int h = m_view_area->height (); int vert_buttons_pos = h - statusBarHeight (); int cp_height = controlPanel ()->maximumSize ().height (); if (cp_height > int (0.25 * h)) cp_height = int (0.25 * h); delayedShowButtons (y > vert_buttons_pos-cp_height && y < vert_buttons_pos); } KDE_NO_EXPORT void View::updateLayout () { if (m_controlpanel_mode == CP_Only) m_control_panel->setMaximumHeight(height()); m_view_area->resizeEvent (0L); } void View::setKeepSizeRatio (bool b) { if (m_keepsizeratio != b) { m_keepsizeratio = b; updateLayout (); m_view_area->update (); } } KDE_NO_EXPORT void View::timerEvent (QTimerEvent * e) { if (e->timerId () == controlbar_timer) { controlbar_timer = 0; if (m_playing || !m_image.isNull ()) { int vert_buttons_pos = m_view_area->height()-statusBarHeight (); QPoint mouse_pos = m_view_area->mapFromGlobal (QCursor::pos ()); int cp_height = m_control_panel->maximumSize ().height (); bool mouse_on_buttons = (//m_view_area->hasMouse () && mouse_pos.y () >= vert_buttons_pos-cp_height && mouse_pos.y ()<= vert_buttons_pos && mouse_pos.x () > 0 && mouse_pos.x () < m_control_panel->width()); if (mouse_on_buttons && !m_control_panel->isVisible ()) { m_control_panel->show (); m_view_area->resizeEvent (0L); } else if (!mouse_on_buttons && m_control_panel->isVisible ()) { m_control_panel->hide (); m_view_area->resizeEvent (0L); } } } else if (e->timerId () == infopanel_timer) { if (m_infopanel->document ()->isEmpty ()) m_dock_infopanel->hide (); //m_dock_infopanel->undock (); infopanel_timer = 0; } else if (e->timerId () == m_restore_state_timer) { m_view_area->setVisible(true); setControlPanelMode (m_old_controlpanel_mode); m_dockarea->restoreState(m_dock_state); m_restore_state_timer = 0; } killTimer (e->timerId ()); } void View::addText (const QString & str, bool eol) { if (m_tmplog_needs_eol) tmplog += QChar ('\n'); tmplog += str; m_tmplog_needs_eol = eol; if (!m_multiedit->isVisible () && tmplog.size () < 7500) return; if (eol) { if (m_multiedit->document ()->isEmpty ()) m_multiedit->setPlainText (tmplog); else m_multiedit->append (tmplog); tmplog.truncate (0); m_tmplog_needs_eol = false; } else { int pos = tmplog.lastIndexOf (QChar ('\n')); if (pos >= 0) { m_multiedit->append (tmplog.left (pos)); tmplog = tmplog.mid (pos+1); } } QTextCursor cursor = m_multiedit->textCursor (); cursor.movePosition (QTextCursor::End); cursor.movePosition (QTextCursor::PreviousBlock, QTextCursor::MoveAnchor, 5000); cursor.movePosition (QTextCursor::Start, QTextCursor::KeepAnchor); cursor.removeSelectedText (); cursor.movePosition (QTextCursor::End); m_multiedit->setTextCursor (cursor); } KDE_NO_EXPORT void View::videoStart () { if (!isFullScreen () && m_dockarea->centralWidget () != m_view_area) { // restore from an info or playlist only setting if (m_dockarea->centralWidget () == m_playlist) m_dock_playlist->setWidget (m_playlist); else if (m_dockarea->centralWidget () == m_infopanel) m_dock_infopanel->setWidget (m_infopanel); else m_status_bar->setVisible (false); m_dockarea->setCentralWidget (m_view_area); } if (m_controlpanel_mode == CP_Only) { m_control_panel->setMaximumHeight(controlPanel()->preferredHeight()); setControlPanelMode (CP_Show); } } KDE_NO_EXPORT void View::playingStart () { if (m_playing) return; //FIXME: make symetric with playingStop m_playing = true; m_revert_fullscreen = !isFullScreen(); setControlPanelMode (m_old_controlpanel_mode); } KDE_NO_EXPORT void View::playingStop () { if (m_controlpanel_mode == CP_AutoHide && m_image.isNull ()) { m_control_panel->show (); //m_view_area->setMouseTracking (false); } if (controlbar_timer) { killTimer (controlbar_timer); controlbar_timer = 0; } m_playing = false; m_view_area->resizeEvent (0L); } KDE_NO_EXPORT void View::leaveEvent (QEvent *) { delayedShowButtons (false); } KDE_NO_EXPORT void View::reset () { if (m_revert_fullscreen && isFullScreen ()) m_control_panel->fullscreenAction->activate (QAction::Trigger); //m_view_area->fullScreen (); playingStop (); } bool View::isFullScreen () const { return m_view_area->isFullScreen (); } void View::fullScreen () { if (m_restore_state_timer) { killTimer (m_restore_state_timer); m_restore_state_timer = 0; } if (!m_view_area->isFullScreen()) { m_sreensaver_disabled = false; m_powerManagerStopSleep = Solid::PowerManagement::beginSuppressingSleep("KMplayer: watching a film"); /*QByteArray data, replydata; QCString replyType; if (kapp->dcopClient ()->call ("kdesktop", "KScreensaverIface", "isEnabled()", data, replyType, replydata)) { bool enabled; QDataStream replystream (replydata, IO_ReadOnly); replystream >> enabled; if (enabled) m_sreensaver_disabled = kapp->dcopClient()->send ("kdesktop", "KScreensaverIface", "enable(bool)", "false"); }*/ //if (m_keepsizeratio && m_viewer->aspect () < 0.01) // m_viewer->setAspect (1.0 * m_viewer->width() / m_viewer->height()); m_dock_state = m_dockarea->saveState(); m_dock_playlist->hide(); m_dock_infopanel->hide(); m_view_area->fullScreen(); m_control_panel->zoomAction->setVisible (false); //if (m_viewer->isVisible ()) // m_viewer->setFocus (); } else { Solid::PowerManagement::stopSuppressingSleep(m_powerManagerStopSleep); // if (m_sreensaver_disabled) // m_sreensaver_disabled = !kapp->dcopClient()->send // ("kdesktop", "KScreensaverIface", "enable(bool)", "true"); m_view_area->fullScreen(); m_control_panel->zoomAction->setVisible (true); m_restore_state_timer = startTimer(100); //dockArea()->restoreState(m_dock_state); } setControlPanelMode (m_old_controlpanel_mode); emit fullScreenChanged (); } KDE_NO_EXPORT int View::statusBarHeight () const { if (statusBar()->isVisible () && !viewArea()->isFullScreen ()) { if (statusBarMode () == SB_Only) return height (); else return statusBar()->maximumSize ().height (); } return 0; } #include "kmplayerview.moc" diff --git a/src/surface.cpp b/src/surface.cpp index 0b753aa..d103522 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1,194 +1,190 @@ /** This file belong to the KMPlayer project, a movie player plugin for Konqueror Copyright (C) 2008 Koos Vriezen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **/ #include "config-kmplayer.h" #ifdef KMPLAYER_WITH_CAIRO # include #endif #include #include #include "surface.h" #include "viewarea.h" using namespace KMPlayer; KDE_NO_CDTOR_EXPORT Surface::Surface (ViewArea *widget) : bounds(SRect(0, 0, -#if QT_VERSION >= 0x050600 widget->width() * widget->devicePixelRatioF(), widget->height() * widget->devicePixelRatioF() -#else - widget->width(), widget->height() -#endif )), xscale (1.0), yscale (1.0), background_color (0), #ifdef KMPLAYER_WITH_CAIRO surface (0L), #endif dirty (false), scroll (false), has_mouse (false), view_widget (widget) {} Surface::~Surface() { #ifdef KMPLAYER_WITH_CAIRO if (surface) cairo_surface_destroy (surface); #endif } template <> void TreeNode::appendChild (Surface *c) { appendChildImpl (c); } template <> void TreeNode::insertBefore (Surface *c, Surface *b) { insertBeforeImpl (c, b); } template <> void TreeNode::removeChild (SurfacePtr c) { removeChildImpl (c); } void Surface::clear () { m_first_child = 0L; background_color = 0; } void Surface::remove () { Surface *sp = parentNode (); if (sp) { sp->markDirty (); sp->removeChild (this); } } void Surface::resize (const SRect &rect, bool parent_resized) { SRect old_bounds = bounds; bounds = rect; if (parent_resized || old_bounds != rect) { if (parent_resized || old_bounds.size != rect.size) { virtual_size = SSize (); //FIXME try to preserve scroll on resize markDirty (); #ifdef KMPLAYER_WITH_CAIRO if (surface) { cairo_surface_destroy (surface); surface = NULL; } #endif updateChildren (true); } else if (parentNode ()) { parentNode ()->markDirty (); } if (parentNode ()) parentNode ()->repaint (old_bounds.unite (rect)); else repaint (); } } void Surface::markDirty () { for (Surface *s = this; s && !s->dirty; s = s->parentNode ()) s->dirty = true; } void Surface::updateChildren (bool parent_resized) { for (Surface *c = firstChild (); c; c = c->nextSibling ()) if (c->node) c->node->message (MsgSurfaceBoundsUpdate, (void *) parent_resized); else kError () << "Surface without node"; } Surface *Surface::createSurface (NodePtr owner, const SRect & rect) { Surface *surface = new Surface (view_widget); surface->node = owner; surface->bounds = rect; appendChild (surface); return surface; } KDE_NO_EXPORT IRect Surface::toScreen (const SSize &size) { //FIXME: handle scroll Matrix matrix (0, 0, xscale, yscale); matrix.translate (bounds.x (), bounds.y ()); for (Surface *s = parentNode(); s; s = s->parentNode()) { matrix.transform(Matrix (0, 0, s->xscale, s->yscale)); matrix.translate (s->bounds.x (), s->bounds.y ()); } return matrix.toScreen (SRect (0, 0, size)); } void Surface::setBackgroundColor (unsigned int argb) { #ifdef KMPLAYER_WITH_CAIRO if (surface && ((background_color & 0xff000000) < 0xff000000) != ((argb & 0xff000000) < 0xff000000)) { cairo_surface_destroy (surface); surface = NULL; } #endif background_color = argb; } static void clipToScreen (Surface *s, Matrix &m, IRect &clip) { Surface *ps = s->parentNode (); if (!ps) { clip = IRect (s->bounds.x (), s->bounds.y (), s->bounds.width (), s->bounds.height ()); m = Matrix (s->bounds.x (), s->bounds.y (), s->xscale, s->yscale); } else { clipToScreen (ps, m, clip); IRect scr = m.toScreen (s->bounds); clip = clip.intersect (scr); Matrix m1 = m; m = Matrix (s->bounds.x (), s->bounds.y (), s->xscale, s->yscale); m.transform (m1); if (!s->virtual_size.isEmpty ()) m.translate (-s->x_scroll, -s->y_scroll); } } KDE_NO_EXPORT void Surface::repaint (const SRect &rect) { Matrix matrix; IRect clip; clipToScreen (this, matrix, clip); IRect scr = matrix.toScreen (rect); clip = clip.intersect (scr); if (!clip.isEmpty ()) view_widget->scheduleRepaint (clip); } KDE_NO_EXPORT void Surface::repaint () { Surface *ps = parentNode (); if (ps) ps->repaint (bounds); else view_widget->scheduleRepaint (IRect (bounds.x (), bounds.y (), bounds.width (), bounds.height ())); } diff --git a/src/viewarea.cpp b/src/viewarea.cpp index 8623b8b..ac2216a 100644 --- a/src/viewarea.cpp +++ b/src/viewarea.cpp @@ -1,2748 +1,2673 @@ /** This file belong to the KMPlayer project, a movie player plugin for Konqueror Copyright (C) 2007 Koos Vriezen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **/ #include "config-kmplayer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmplayerview.h" #include "kmplayercontrolpanel.h" #include "playlistview.h" #include "viewarea.h" #ifdef KMPLAYER_WITH_CAIRO # include #endif #include "mediaobject.h" #include "kmplayer_smil.h" #include "kmplayer_rp.h" #include "mediaobject.h" #include #include using namespace KMPlayer; -#if QT_VERSION >= 0x050600 static qreal pixel_device_ratio; -#endif + //------------------------------------------------------------------------- #ifdef KMPLAYER_WITH_CAIRO static void clearSurface (cairo_t *cr, const IRect &rect) { cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_rectangle (cr, rect.x (), rect.y (), rect.width (), rect.height ()); cairo_fill (cr); cairo_restore (cr); } void ImageData::copyImage (Surface *s, const SSize &sz, cairo_surface_t *similar, CalculatedSizer *zoom) { cairo_surface_t *src_sf; bool clear = false; int w = sz.width; int h = sz.height; if (surface) { src_sf = surface; } else { if (image->depth () < 24) { QImage qi = image->convertToFormat (QImage::Format_RGB32); *image = qi; } src_sf = cairo_image_surface_create_for_data ( image->bits (), has_alpha ? CAIRO_FORMAT_ARGB32:CAIRO_FORMAT_RGB24, width, height, image->bytesPerLine ()); if (flags & ImagePixmap && !(flags & ImageAnimated)) { surface = cairo_surface_create_similar (similar, has_alpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR, width, height); cairo_pattern_t *pat = cairo_pattern_create_for_surface (src_sf); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_t *cr = cairo_create (surface); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source (cr, pat); cairo_paint (cr); cairo_destroy (cr); cairo_pattern_destroy (pat); cairo_surface_destroy (src_sf); src_sf = surface; delete image; image = NULL; } } cairo_pattern_t *img_pat = cairo_pattern_create_for_surface (src_sf); cairo_pattern_set_extend (img_pat, CAIRO_EXTEND_NONE); if (zoom) { cairo_matrix_t mat; Single zx, zy, zw, zh; zoom->calcSizes (NULL, NULL, width, height, zx, zy, zw, zh); cairo_matrix_init_translate (&mat, zx, zy); cairo_matrix_scale (&mat, 1.0 * zw/w, 1.0 * zh/h); cairo_pattern_set_matrix (img_pat, &mat); } else if (w != width && h != height) { cairo_matrix_t mat; cairo_matrix_init_scale (&mat, 1.0 * width/w, 1.0 * height/h); cairo_pattern_set_matrix (img_pat, &mat); } if (!s->surface) s->surface = cairo_surface_create_similar (similar, has_alpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR, w, h); else clear = true; cairo_t *cr = cairo_create (s->surface); if (clear) clearSurface (cr, IRect (0, 0, w, h)); cairo_set_source (cr, img_pat); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_destroy (cr); cairo_pattern_destroy (img_pat); if (!surface) cairo_surface_destroy (src_sf); } #endif //------------------------------------------------------------------------- #define REGION_SCROLLBAR_WIDTH 20 #ifdef KMPLAYER_WITH_CAIRO # define CAIRO_SET_SOURCE_RGB(cr,c) \ cairo_set_source_rgb ((cr), \ 1.0 * (((c) >> 16) & 0xff) / 255, \ 1.0 * (((c) >> 8) & 0xff) / 255, \ 1.0 * (((c)) & 0xff) / 255) # define CAIRO_SET_SOURCE_ARGB(cr,c) \ cairo_set_source_rgba ((cr), \ 1.0 * (((c) >> 16) & 0xff) / 255, \ 1.0 * (((c) >> 8) & 0xff) / 255, \ 1.0 * (((c)) & 0xff) / 255, \ 1.0 * (((c) >> 24) & 0xff) / 255) struct KMPLAYER_NO_EXPORT PaintContext { PaintContext (const Matrix& m, const IRect& c) : matrix (m) , clip (c) , fit (fit_default) , bg_repeat (SMIL::RegionBase::BgRepeat) , bg_image (NULL) {} Matrix matrix; IRect clip; Fit fit; SMIL::RegionBase::BackgroundRepeat bg_repeat; ImageData *bg_image; }; class KMPLAYER_NO_EXPORT CairoPaintVisitor : public Visitor, public PaintContext { cairo_surface_t * cairo_surface; // stack vars need for transitions TransitionModule *cur_transition; cairo_pattern_t * cur_pat; cairo_matrix_t cur_mat; float opacity; bool toplevel; void traverseRegion (Node *reg, Surface *s); void updateExternal (SMIL::MediaType *av, SurfacePtr s); void paint (TransitionModule *trans, MediaOpacity mopacity, Surface *s, const IPoint &p, const IRect &); void video (Mrl *mt, Surface *s); public: cairo_t * cr; CairoPaintVisitor (cairo_surface_t * cs, Matrix m, const IRect & rect, QColor c=QColor(), bool toplevel=false); ~CairoPaintVisitor (); using Visitor::visit; void visit (Node *); void visit (SMIL::Smil *); void visit (SMIL::Layout *); void visit (SMIL::RegionBase *); void visit (SMIL::Transition *); void visit (SMIL::TextMediaType *); void visit (SMIL::Brush *); void visit (SMIL::SmilText *); void visit (SMIL::RefMediaType *); void visit (RP::Imfl *); void visit (RP::Fill *); void visit (RP::Fadein *); void visit (RP::Fadeout *); void visit (RP::Crossfade *); void visit (RP::Wipe *); void visit (RP::ViewChange *); }; KDE_NO_CDTOR_EXPORT CairoPaintVisitor::CairoPaintVisitor (cairo_surface_t * cs, Matrix m, const IRect & rect, QColor c, bool top) : PaintContext (m, rect), cairo_surface (cs), toplevel (top) { cr = cairo_create (cs); if (toplevel) { cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_tolerance (cr, 0.5 ); //cairo_push_group (cr); cairo_set_source_rgb (cr, 1.0 * c.red () / 255, 1.0 * c.green () / 255, 1.0 * c.blue () / 255); cairo_rectangle (cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_fill (cr); } else { clearSurface (cr, rect); } } KDE_NO_CDTOR_EXPORT CairoPaintVisitor::~CairoPaintVisitor () { /*if (toplevel) { cairo_pattern_t * pat = cairo_pop_group (cr); //cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_set_source (cr, pat); cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h); cairo_fill (cr); cairo_pattern_destroy (pat); }*/ cairo_destroy (cr); } KDE_NO_EXPORT void CairoPaintVisitor::visit (Node * n) { kWarning() << "Paint called on " << n->nodeName(); } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Smil *s) { if (s->active () && s->layout_node) s->layout_node->accept (this); } KDE_NO_EXPORT void CairoPaintVisitor::traverseRegion (Node *node, Surface *s) { ConnectionList *nl = nodeMessageReceivers (node, MsgSurfaceAttach); if (nl) { for (Connection *c = nl->first(); c; c = nl->next ()) if (c->connecter) c->connecter->accept (this); } /*for (SurfacePtr c = s->lastChild (); c; c = c->previousSibling ()) { if (c->node && c->node->id != SMIL::id_node_region && c->node && c->node->id != SMIL::id_node_root_layout) c->node->accept (this); else break; }*/ // finally visit region children for (SurfacePtr c = s->firstChild (); c; c = c->nextSibling ()) { if (c->node && c->node->id == SMIL::id_node_region) c->node->accept (this); else break; } s->dirty = false; } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Layout *layout) { if (layout->root_layout) layout->root_layout->accept (this); } static void cairoDrawRect (cairo_t *cr, unsigned int color, int x, int y, int w, int h) { CAIRO_SET_SOURCE_ARGB (cr, color); cairo_rectangle (cr, x, y, w, h); cairo_fill (cr); } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::RegionBase *reg) { Surface *s = (Surface *) reg->role (RoleDisplay); if (s) { SRect rect = s->bounds; IRect scr = matrix.toScreen (rect); if (clip.intersect (scr).isEmpty ()) return; PaintContext ctx_save = *(PaintContext *) this; matrix = Matrix (rect.x(), rect.y(), s->xscale, s->yscale); matrix.transform (ctx_save.matrix); clip = clip.intersect (scr); if (SMIL::RegionBase::BgInherit != reg->bg_repeat) bg_repeat = reg->bg_repeat; cairo_save (cr); Surface *cs = s->firstChild (); if (!s->virtual_size.isEmpty ()) matrix.translate (-s->x_scroll, -s->y_scroll); if (fit_default != reg->fit) fit = reg->fit; ImageMedia *im = reg->media_info ? (ImageMedia *) reg->media_info->media : NULL; ImageData *bg_img = im && !im->isEmpty() ? im->cached_img.ptr () : NULL; if (reg->background_image == "inherit") bg_img = bg_image; else bg_image = bg_img; unsigned int bg_alpha = s->background_color & 0xff000000; if ((SMIL::RegionBase::ShowAlways == reg->show_background || reg->m_AttachedMediaTypes.first ()) && (bg_alpha || bg_img)) { cairo_save (cr); if (bg_alpha) { cairo_rectangle (cr, clip.x (), clip.y (), clip.width (), clip.height ()); if (bg_alpha < 0xff000000) { CAIRO_SET_SOURCE_ARGB (cr, s->background_color); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_fill (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); } else { CAIRO_SET_SOURCE_RGB (cr, s->background_color); cairo_fill (cr); } } if (bg_img) { Single w = bg_img->width; Single h = bg_img->height; matrix.getWH (w, h); if (!s->surface) bg_img->copyImage (s, SSize (w, h), cairo_surface); if (bg_img->has_alpha) cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_pattern_t *pat = cairo_pattern_create_for_surface (s->surface); cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT); cairo_matrix_t mat; cairo_matrix_init_translate (&mat, -scr.x (), -scr.y ()); cairo_pattern_set_matrix (pat, &mat); cairo_set_source (cr, pat); int cw = clip.width (); int ch = clip.height (); switch (bg_repeat) { case SMIL::RegionBase::BgRepeatX: if (h < ch) ch = h; break; case SMIL::RegionBase::BgRepeatY: if (w < cw) cw = w; break; case SMIL::RegionBase::BgNoRepeat: if (w < cw) cw = w; if (h < ch) ch = h; break; default: break; } cairo_rectangle (cr, clip.x (), clip.y (), cw, ch); cairo_fill (cr); cairo_pattern_destroy (pat); if (bg_img->has_alpha) cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); } cairo_restore (cr); } traverseRegion (reg, s); cs = s->firstChild (); if (cs && (s->scroll || cs->scroll) && cs == s->lastChild ()) { SRect r = cs->bounds; if (r.width () > rect.width () || r.height () > rect.height ()) { if (s->virtual_size.isEmpty ()) s->x_scroll = s->y_scroll = 0; s->virtual_size = r.size; matrix.getWH (s->virtual_size.width, s->virtual_size.height); s->virtual_size.width += REGION_SCROLLBAR_WIDTH; s->virtual_size.height += REGION_SCROLLBAR_WIDTH; const int vy = s->virtual_size.height; const int vw = s->virtual_size.width; int sbw = REGION_SCROLLBAR_WIDTH; int sbx = scr.x () + scr.width () - sbw; int sby = scr.y (); int sbh = scr.height () - REGION_SCROLLBAR_WIDTH; IRect sb_clip = clip.intersect (IRect (sbx, sby, sbw, sbh)); if (!sb_clip.isEmpty ()) { int knob_h = sbh * scr.height () / vy; int knob_y = scr.y () + s->y_scroll * sbh / vy; IRect knob (sbx, knob_y, sbw, knob_h); cairo_save (cr); cairo_rectangle (cr, sb_clip.x (), sb_clip.y (), sb_clip.width (), sb_clip.height ()); cairo_clip (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_line_width (cr, 2); CAIRO_SET_SOURCE_ARGB (cr, 0x80A0A0A0); cairo_rectangle (cr, sbx + 1, sby + 1, sbw - 2, sbh - 2); cairo_stroke (cr); if (s->y_scroll) cairoDrawRect (cr, 0x80000000, sbx + 2, sby + 2, sbw - 4, knob.y() - sby - 2); cairoDrawRect (cr, 0x80808080, knob.x() + 2, knob.y(), knob.width() - 4, knob.height()); if (sby + sbh - knob.y() - knob.height() - 2 > 0) cairoDrawRect (cr, 0x80000000, sbx + 2, knob.y() + knob.height(), sbw - 4, sby + sbh - knob.y() -knob.height()-2); cairo_restore (cr); } sbh = REGION_SCROLLBAR_WIDTH; sbx = scr.x (); sby = scr.y () + scr.height () - sbh; sbw = scr.width () - REGION_SCROLLBAR_WIDTH; sb_clip = clip.intersect (IRect (sbx, sby, sbw, sbh)); if (!sb_clip.isEmpty ()) { int knob_w = sbw * scr.width () / vw; int knob_x = scr.x () + s->x_scroll * sbw / vw; IRect knob (knob_x, sby, knob_w, sbh); cairo_save (cr); cairo_rectangle (cr, sb_clip.x (), sb_clip.y (), sb_clip.width (), sb_clip.height ()); cairo_clip (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_line_width (cr, 2); CAIRO_SET_SOURCE_ARGB (cr, 0x80A0A0A0); cairo_rectangle (cr, sbx + 1, sby + 1, sbw - 2, sbh - 2); cairo_stroke (cr); if (s->x_scroll) cairoDrawRect (cr, 0x80000000, sbx + 2, sby + 2, knob.x() - sbx - 2, sbh - 4); cairoDrawRect (cr, 0x80808080, knob.x(), knob.y() + 2, knob.width(), knob.height() - 4); if (sbx + sbw - knob.x() - knob.width() - 2 > 0) cairoDrawRect (cr, 0x80000000, knob.x() + knob.width(), sby + 2, sbx + sbw - knob.x() - knob.width()-2, sbh - 4); cairo_restore (cr); } } } cairo_restore (cr); *(PaintContext *) this = ctx_save; s->dirty = false; } } #define CAIRO_SET_PATTERN_COND(cr,pat,mat) \ if (pat) { \ cairo_pattern_set_extend (cur_pat, CAIRO_EXTEND_NONE); \ cairo_pattern_set_matrix (pat, &mat); \ cairo_pattern_set_filter (pat, CAIRO_FILTER_FAST); \ cairo_set_source (cr, pat); \ } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Transition *trans) { float perc = trans->start_progress + (trans->end_progress - trans->start_progress)*cur_transition->trans_gain; if (cur_transition->trans_out_active) perc = 1.0 - perc; if (SMIL::Transition::Fade == trans->type) { CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) cairo_rectangle (cr, clip.x(), clip.y(), clip.width(), clip.height()); opacity = perc; } else if (SMIL::Transition::BarWipe == trans->type) { IRect rect; if (SMIL::Transition::SubTopToBottom == trans->sub_type) { if (SMIL::Transition::dir_reverse == trans->direction) { int dy = (int) ((1.0 - perc) * clip.height ()); rect = IRect (clip.x (), clip.y () + dy, clip.width (), clip.height () - dy); } else { rect = IRect (clip.x (), clip.y (), clip.width (), (int) (perc * clip.height ())); } } else { if (SMIL::Transition::dir_reverse == trans->direction) { int dx = (int) ((1.0 - perc) * clip.width ()); rect = IRect (clip.x () + dx, clip.y (), clip.width () - dx, clip.height ()); } else { rect = IRect (clip.x (), clip.y (), (int) (perc * clip.width ()), clip.height ()); } } cairo_rectangle (cr, rect.x(), rect.y(), rect.width(), rect.height()); CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) } else if (SMIL::Transition::PushWipe == trans->type) { int dx = 0, dy = 0; if (SMIL::Transition::SubFromTop == trans->sub_type) dy = -(int) ((1.0 - perc) * clip.height ()); else if (SMIL::Transition::SubFromRight == trans->sub_type) dx = (int) ((1.0 - perc) * clip.width ()); else if (SMIL::Transition::SubFromBottom == trans->sub_type) dy = (int) ((1.0 - perc) * clip.height ()); else //if (SMIL::Transition::SubFromLeft == trans->sub_type) dx = -(int) ((1.0 - perc) * clip.width ()); cairo_matrix_translate (&cur_mat, -dx, -dy); IRect rect = clip.intersect (IRect (clip.x () + dx, clip.y () + dy, clip.width (), clip.height ())); cairo_rectangle (cr, rect.x(), rect.y(), rect.width(), rect.height()); CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) } else if (SMIL::Transition::IrisWipe == trans->type) { CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) if (SMIL::Transition::SubDiamond == trans->sub_type) { cairo_rectangle (cr, clip.x(), clip.y(),clip.width(),clip.height()); cairo_clip (cr); int dx = (int) (perc * clip.width ()); int dy = (int) (perc * clip.height ()); int mx = clip.x () + clip.width ()/2; int my = clip.y () + clip.height ()/2; cairo_new_path (cr); cairo_move_to (cr, mx, my - dy); cairo_line_to (cr, mx + dx, my); cairo_line_to (cr, mx, my + dy); cairo_line_to (cr, mx - dx, my); cairo_close_path (cr); } else { // SubRectangle int dx = (int) (0.5 * (1 - perc) * clip.width ()); int dy = (int) (0.5 * (1 - perc) * clip.height ()); cairo_rectangle (cr, clip.x () + dx, clip.y () + dy, clip.width () - 2 * dx, clip.height () -2 * dy); } } else if (SMIL::Transition::ClockWipe == trans->type) { cairo_rectangle (cr, clip.x(), clip.y(), clip.width(), clip.height()); cairo_clip (cr); int mx = clip.x () + clip.width ()/2; int my = clip.y () + clip.height ()/2; cairo_new_path (cr); cairo_move_to (cr, mx, my); float hw = 1.0 * clip.width ()/2; float hh = 1.0 * clip.height ()/2; float radius = sqrtf (hw * hw + hh * hh); float phi; switch (trans->sub_type) { case SMIL::Transition::SubClockwiseThree: phi = 0; break; case SMIL::Transition::SubClockwiseSix: phi = M_PI / 2; break; case SMIL::Transition::SubClockwiseNine: phi = M_PI; break; default: // Twelve phi = -M_PI / 2; break; } if (SMIL::Transition::dir_reverse == trans->direction) cairo_arc_negative (cr, mx, my, radius, phi, phi - 2 * M_PI * perc); else cairo_arc (cr, mx, my, radius, phi, phi + 2 * M_PI * perc); cairo_close_path (cr); CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) } else if (SMIL::Transition::BowTieWipe == trans->type) { cairo_rectangle (cr, clip.x(), clip.y(), clip.width(), clip.height()); cairo_clip (cr); int mx = clip.x () + clip.width ()/2; int my = clip.y () + clip.height ()/2; cairo_new_path (cr); cairo_move_to (cr, mx, my); float hw = 1.0 * clip.width ()/2; float hh = 1.0 * clip.height ()/2; float radius = sqrtf (hw * hw + hh * hh); float phi; switch (trans->sub_type) { case SMIL::Transition::SubHorizontal: phi = 0; break; default: // Vertical phi = -M_PI / 2; break; } float dphi = 0.5 * M_PI * perc; cairo_arc (cr, mx, my, radius, phi - dphi, phi + dphi); cairo_close_path (cr); cairo_new_sub_path (cr); cairo_move_to (cr, mx, my); if (SMIL::Transition::SubHorizontal == trans->sub_type) cairo_arc (cr, mx, my, radius, M_PI + phi - dphi, M_PI + phi +dphi); else cairo_arc (cr, mx, my, radius, -phi - dphi, -phi + dphi); cairo_close_path (cr); CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) } else if (SMIL::Transition::EllipseWipe == trans->type) { cairo_rectangle (cr, clip.x(), clip.y(), clip.width(), clip.height()); cairo_clip (cr); int mx = clip.x () + clip.width ()/2; int my = clip.y () + clip.height ()/2; float hw = (double) clip.width ()/2; float hh = (double) clip.height ()/2; float radius = sqrtf (hw * hw + hh * hh); cairo_save (cr); cairo_new_path (cr); cairo_translate (cr, (int) mx, (int) my); cairo_move_to (cr, - Single (radius), 0); if (SMIL::Transition::SubHorizontal == trans->sub_type) cairo_scale (cr, 1.0, 0.6); else if (SMIL::Transition::SubVertical == trans->sub_type) cairo_scale (cr, 0.6, 1.0); cairo_arc (cr, 0, 0, perc * radius, 0, 2 * M_PI); cairo_close_path (cr); cairo_restore (cr); CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat) } } KDE_NO_EXPORT void CairoPaintVisitor::video (Mrl *m, Surface *s) { if (m->media_info && m->media_info->media && (MediaManager::Audio == m->media_info->type || MediaManager::AudioVideo == m->media_info->type)) { AudioVideoMedia *avm = static_cast (m->media_info->media); if (avm->viewer ()) { if (s && avm->process && avm->process->state () > IProcess::Ready && strcmp (m->nodeName (), "audio")) { s->xscale = s->yscale = 1; // either scale width/height or use bounds avm->viewer ()->setGeometry (s->toScreen (s->bounds.size)); } else { avm->viewer ()->setGeometry (IRect (-60, -60, 50, 50)); } } } } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::RefMediaType *ref) { Surface *s = ref->surface (); if (s && ref->external_tree) { updateExternal (ref, s); return; } if (!ref->media_info) return; if (fit_default != fit && fit_default == ref->fit && fit != ref->effective_fit) { ref->effective_fit = fit; s->resize (ref->calculateBounds(), false); } if (ref->media_info->media && ref->media_info->media->type () == MediaManager::Image) { if (!s) return; IRect scr = matrix.toScreen (s->bounds); IRect clip_rect = clip.intersect (scr); if (clip_rect.isEmpty ()) return; ImageMedia *im = static_cast (ref->media_info->media); ImageData *id = im ? im->cached_img.ptr () : NULL; if (id && id->flags == ImageData::ImageScalable) im->render (scr.size); if (!id || im->isEmpty () || ref->size.isEmpty ()) { s->remove(); return; } if (!s->surface || s->dirty) id->copyImage (s, SSize (scr.width (), scr.height ()), cairo_surface, ref->pan_zoom); paint (&ref->transition, ref->media_opacity, s, scr.point, clip_rect); s->dirty = false; } else { video (ref, s); } } KDE_NO_EXPORT void CairoPaintVisitor::paint (TransitionModule *trans, MediaOpacity mopacity, Surface *s, const IPoint &point, const IRect &rect) { cairo_save (cr); opacity = 1.0; cairo_matrix_init_translate (&cur_mat, -point.x, -point.y); cur_pat = cairo_pattern_create_for_surface (s->surface); if (trans->active_trans) { IRect clip_save = clip; clip = rect; cur_transition = trans; trans->active_trans->accept (this); clip = clip_save; } else { cairo_pattern_set_extend (cur_pat, CAIRO_EXTEND_NONE); cairo_pattern_set_matrix (cur_pat, &cur_mat); cairo_pattern_set_filter (cur_pat, CAIRO_FILTER_FAST); cairo_set_source (cr, cur_pat); cairo_rectangle (cr, rect.x(), rect.y(), rect.width(), rect.height()); } opacity *= mopacity.opacity / 100.0; bool over = opacity < 0.99 || CAIRO_CONTENT_COLOR != cairo_surface_get_content (s->surface); cairo_operator_t op; if (over) { op = cairo_get_operator (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); } if (opacity < 0.99) { cairo_clip (cr); cairo_paint_with_alpha (cr, opacity); } else { cairo_fill (cr); } if (over) cairo_set_operator (cr, op); cairo_pattern_destroy (cur_pat); cairo_restore (cr); } static Mrl *findActiveMrl (Node *n, bool *rp_or_smil) { Mrl *mrl = n->mrl (); if (mrl) { *rp_or_smil = (mrl->id >= SMIL::id_node_first && mrl->id < SMIL::id_node_last) || (mrl->id >= RP::id_node_first && mrl->id < RP::id_node_last); if (*rp_or_smil || (mrl->media_info && (MediaManager::Audio == mrl->media_info->type || MediaManager::AudioVideo == mrl->media_info->type))) return mrl; } for (Node *c = n->firstChild (); c; c = c->nextSibling ()) if (c->active ()) { Mrl *m = findActiveMrl (c, rp_or_smil); if (m) return m; } return NULL; } KDE_NO_EXPORT void CairoPaintVisitor::updateExternal (SMIL::MediaType *av, SurfacePtr s) { bool rp_or_smil = false; Mrl *ext_mrl = findActiveMrl (av->external_tree.ptr (), &rp_or_smil); if (!ext_mrl) return; if (!rp_or_smil) { video (ext_mrl, s.ptr ()); return; } IRect scr = matrix.toScreen (s->bounds); IRect clip_rect = clip.intersect (scr); if (clip_rect.isEmpty ()) return; if (!s->surface || s->dirty) { Matrix m = matrix; m.translate (-scr.x (), -scr.y ()); m.scale (s->xscale, s->yscale); IRect r (clip_rect.x() - scr.x () - 1, clip_rect.y() - scr.y () - 1, clip_rect.width() + 3, clip_rect.height() + 3); if (!s->surface) { s->surface = cairo_surface_create_similar (cairo_surface, CAIRO_CONTENT_COLOR_ALPHA, scr.width (), scr.height ()); r = IRect (0, 0, scr.size); } CairoPaintVisitor visitor (s->surface, m, r); ext_mrl->accept (&visitor); s->dirty = false; } paint (&av->transition, av->media_opacity, s.ptr (), scr.point, clip_rect); } static void setAlignment (QTextDocument &td, unsigned char align) { QTextOption opt = td.defaultTextOption(); if (SmilTextProperties::AlignLeft == align) opt.setAlignment (Qt::AlignLeft); else if (SmilTextProperties::AlignCenter == align) opt.setAlignment (Qt::AlignCenter); else if (SmilTextProperties::AlignRight == align) opt.setAlignment (Qt::AlignRight); td.setDefaultTextOption (opt); } static void calculateTextDimensions (const QFont& font, const QString& text, Single w, Single h, Single maxh, int *pxw, int *pxh, bool markup_text, unsigned char align = SmilTextProperties::AlignLeft) { QTextDocument td; td.setDefaultFont( font ); td.setDocumentMargin (0); QImage img (QSize ((int)w, (int)h), QImage::Format_RGB32); td.setPageSize (QSize ((int)w, (int)maxh)); td.documentLayout()->setPaintDevice (&img); if (markup_text) td.setHtml( text ); else td.setPlainText( text ); setAlignment (td, align); QRectF r = td.documentLayout()->blockBoundingRect (td.lastBlock()); *pxw = (int)td.idealWidth (); *pxh = (int)(r.y() + r.height()); -#if QT_VERSION >= 0x050600 *pxw = qMin( (int)(*pxw + pixel_device_ratio), (int)w); -#endif } static cairo_t *createContext (cairo_surface_t *similar, Surface *s, int w, int h) { unsigned int bg_alpha = s->background_color & 0xff000000; bool clear = s->surface; if (!s->surface) s->surface = cairo_surface_create_similar (similar, bg_alpha < 0xff000000 ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR, w, h); cairo_t *cr = cairo_create (s->surface); if (clear) clearSurface (cr, IRect (0, 0, w, h)); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); if (bg_alpha) { if (bg_alpha < 0xff000000) CAIRO_SET_SOURCE_ARGB (cr, s->background_color); else CAIRO_SET_SOURCE_RGB (cr, s->background_color); cairo_paint (cr); } return cr; } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::TextMediaType * txt) { if (!txt->media_info || !txt->media_info->media) return; TextMedia *tm = static_cast (txt->media_info->media); Surface *s = txt->surface (); if (!s) return; if (!s->surface) { txt->size = SSize (); s->bounds = txt->calculateBounds (); } IRect scr = matrix.toScreen (s->bounds); if (!s->surface || s->dirty) { int w = scr.width (); int pxw, pxh; Single ft_size = w * txt->font_size / (double)s->bounds.width (); bool clear = s->surface; QFont font (txt->font_name); font.setPixelSize(ft_size); if (clear) { pxw = scr.width (); pxh = scr.height (); } else { calculateTextDimensions (font, tm->text, w, 2 * ft_size, scr.height (), &pxw, &pxh, false); } QTextDocument td; td.setDocumentMargin (0); td.setDefaultFont (font); bool have_alpha = (s->background_color & 0xff000000) < 0xff000000; QImage img (QSize (pxw, pxh), have_alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); img.fill (s->background_color); td.setPageSize (QSize (pxw, pxh + (int)ft_size)); td.documentLayout()->setPaintDevice (&img); setAlignment (td, 1 + (int)txt->halign); td.setPlainText (tm->text); QPainter painter; painter.begin (&img); QAbstractTextDocumentLayout::PaintContext ctx; ctx.clip = QRect (0, 0, pxw, pxh); ctx.palette.setColor (QPalette::Text, QColor (QRgb (txt->font_color))); td.documentLayout()->draw (&painter, ctx); painter.end(); cairo_t *cr_txt = createContext (cairo_surface, s, pxw, pxh); cairo_surface_t *src_sf = cairo_image_surface_create_for_data ( img.bits (), have_alpha ? CAIRO_FORMAT_ARGB32:CAIRO_FORMAT_RGB24, img.width(), img.height(), img.bytesPerLine ()); cairo_pattern_t *pat = cairo_pattern_create_for_surface (src_sf); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_set_operator (cr_txt, CAIRO_OPERATOR_SOURCE); cairo_set_source (cr_txt, pat); cairo_paint (cr_txt); cairo_pattern_destroy (pat); cairo_surface_destroy (src_sf); cairo_destroy (cr_txt); // update bounds rect SRect rect = matrix.toUser (IRect (scr.point, ISize (pxw, pxh))); txt->size = rect.size; s->bounds = txt->calculateBounds (); // update coord. for painting below scr = matrix.toScreen (s->bounds); } IRect clip_rect = clip.intersect (scr); if (!clip_rect.isEmpty ()) paint (&txt->transition, txt->media_opacity, s, scr.point, clip_rect); s->dirty = false; } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Brush * brush) { Surface *s = brush->surface (); if (s) { opacity = 1.0; IRect clip_rect = clip.intersect (matrix.toScreen (s->bounds)); if (clip_rect.isEmpty ()) return; cairo_save (cr); if (brush->transition.active_trans) { cur_transition = &brush->transition; cur_pat = NULL; brush->transition.active_trans->accept (this); } else { cairo_rectangle (cr, clip_rect.x (), clip_rect.y (), clip_rect.width (), clip_rect.height ()); } unsigned int color = brush->color.color; if (!color) { color = brush->background_color.color; opacity *= brush->background_color.opacity / 100.0; } else { opacity *= brush->color.opacity / 100.0; } opacity *= brush->media_opacity.opacity / 100.0; if (opacity < 0.99) { cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, 1.0 * ((color >> 16) & 0xff) / 255, 1.0 * ((color >> 8) & 0xff) / 255, 1.0 * (color & 0xff) / 255, opacity); } else { CAIRO_SET_SOURCE_RGB (cr, color); } cairo_fill (cr); if (opacity < 0.99) cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); s->dirty = false; cairo_restore (cr); } } struct SmilTextBlock { SmilTextBlock (const QFont& f, const QString &t, IRect r, unsigned char a) : font (f), rich_text (t), rect (r), align (a), next (NULL) {} QFont font; QString rich_text; IRect rect; unsigned char align; SmilTextBlock *next; }; struct KMPLAYER_NO_EXPORT SmilTextInfo { SmilTextInfo (const SmilTextProperties &p) : props (p) {} void span (float scale); SmilTextProperties props; QString span_text; }; class KMPLAYER_NO_EXPORT SmilTextVisitor : public Visitor { public: SmilTextVisitor (int w, float s, const SmilTextProperties &p) : first (NULL), last (NULL), width (w), voffset (0), scale (s), max_font_size (0), info (p) { info.span (scale); } using Visitor::visit; void visit (TextNode *); void visit (SMIL::TextFlow *); void visit (SMIL::TemporalMoment *); void addRichText (const QString &txt); void push (); SmilTextBlock *first; SmilTextBlock *last; int width; int voffset; float scale; float max_font_size; SmilTextInfo info; QString rich_text; }; void SmilTextInfo::span (float scale) { QString s = " -1) s += "font-size:" + QString::number ((int)(scale * props.font_size.size ())) + "px;"; s += "font-family:" + props.font_family + ";"; if (props.font_color > -1) s += QString().sprintf ("color:#%06x;", props.font_color); if (props.background_color > -1) s += QString().sprintf ("background-color:#%06x;", props.background_color); if (SmilTextProperties::StyleInherit != props.font_style) { s += "font-style:"; switch (props.font_style) { case SmilTextProperties::StyleOblique: s += "oblique;"; break; case SmilTextProperties::StyleItalic: s += "italic;"; break; default: s += "normal;"; break; } } if (SmilTextProperties::WeightInherit != props.font_weight) { s += "font-weight:"; switch (props.font_weight) { case SmilTextProperties::WeightBold: s += "bold;"; break; default: s += "normal;"; break; } } s += "\">"; span_text = s; } void SmilTextVisitor::addRichText (const QString &txt) { if (!info.span_text.isEmpty ()) rich_text += info.span_text; rich_text += txt; if (!info.span_text.isEmpty ()) rich_text += ""; } void SmilTextVisitor::push () { if (!rich_text.isEmpty ()) { int pxw, pxh; float fs = info.props.font_size.size (); if (fs < 0) fs = TextMedia::defaultFontSize (); float maxfs = max_font_size; if (maxfs < 1.0) maxfs = fs; fs *= scale; maxfs *= scale; QFont font ("Sans"); font.setPixelSize((int)fs); calculateTextDimensions (font, rich_text.toUtf8 ().constData (), width, 2 * maxfs, 1024, &pxw, &pxh, true, info.props.text_align); int x = 0; if (SmilTextProperties::AlignCenter == info.props.text_align) x = (width - pxw) / 2; else if (SmilTextProperties::AlignRight == info.props.text_align) x = width - pxw; SmilTextBlock *block = new SmilTextBlock (font, rich_text, IRect (x, voffset, pxw, pxh), info.props.text_align); voffset += pxh; max_font_size = 0; rich_text.clear(); if (!first) { first = last = block; } else { last->next = block; last = block; } } } void SmilTextVisitor::visit (TextNode *text) { QString buffer; QTextStream out (&buffer, QIODevice::WriteOnly); out << XMLStringlet (text->nodeValue ()); addRichText (buffer); if (text->nextSibling ()) text->nextSibling ()->accept (this); } void SmilTextVisitor::visit (SMIL::TextFlow *flow) { bool new_block = SMIL::id_node_p == flow->id || SMIL::id_node_br == flow->id || SMIL::id_node_div == flow->id; if ((new_block && !rich_text.isEmpty ()) || flow->firstChild ()) { float fs = info.props.font_size.size (); if (fs < 0) fs = TextMedia::defaultFontSize (); int par_extra = SMIL::id_node_p == flow->id ? (int)(scale * fs) : 0; voffset += par_extra; SmilTextInfo saved_info = info; if (new_block) push (); info.props.mask (flow->props); if ((float)info.props.font_size.size () > max_font_size) max_font_size = info.props.font_size.size (); info.span (scale); if (flow->firstChild ()) flow->firstChild ()->accept (this); if (rich_text.isEmpty ()) par_extra = 0; if (new_block && flow->firstChild ()) push (); voffset += par_extra; info = saved_info; } if (flow->nextSibling ()) flow->nextSibling ()->accept (this); } void SmilTextVisitor::visit (SMIL::TemporalMoment *tm) { if (tm->state >= Node::state_began && tm->nextSibling ()) tm->nextSibling ()->accept (this); } KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::SmilText *txt) { Surface *s = txt->surface (); if (!s) return; SRect rect = s->bounds; IRect scr = matrix.toScreen (rect); if (!s->surface) { int w = scr.width (); float scale = 1.0 * w / (double)s->bounds.width (); SmilTextVisitor info (w, scale, txt->props); Node *first = txt->firstChild (); for (Node *n = first; n; n = n->nextSibling ()) if (SMIL::id_node_clear == n->id) { if (n->state >= Node::state_began) first = n->nextSibling (); else break; } if (first) first->accept (&info); info.push (); if (info.first) { cairo_t *cr_txt = createContext (cairo_surface, s, (int) w, info.voffset); CAIRO_SET_SOURCE_RGB (cr_txt, 0); SmilTextBlock *b = info.first; int hoff = 0; int voff = 0; while (b) { cairo_translate (cr_txt, b->rect.x() - hoff, b->rect.y() - voff); QTextDocument td; td.setDocumentMargin (0); td.setDefaultFont (b->font); bool have_alpha = (s->background_color & 0xff000000) < 0xff000000; QImage img (QSize (b->rect.width(), b->rect.height()), have_alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); img.fill (s->background_color); td.setPageSize (QSize (b->rect.width(), b->rect.height() + 10)); setAlignment (td, b->align); td.documentLayout()->setPaintDevice (&img); td.setHtml (b->rich_text); QPainter painter; painter.begin (&img); QAbstractTextDocumentLayout::PaintContext ctx; ctx.clip = QRect (QPoint (0, 0), img.size ()); td.documentLayout()->draw (&painter, ctx); painter.end(); cairo_surface_t *src_sf = cairo_image_surface_create_for_data ( img.bits (), have_alpha ? CAIRO_FORMAT_ARGB32:CAIRO_FORMAT_RGB24, img.width(), img.height(), img.bytesPerLine ()); cairo_pattern_t *pat = cairo_pattern_create_for_surface (src_sf); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_set_operator (cr_txt, CAIRO_OPERATOR_SOURCE); cairo_set_source (cr_txt, pat); cairo_rectangle (cr_txt, 0, 0, b->rect.width(), b->rect.height()); cairo_fill (cr_txt); cairo_pattern_destroy (pat); cairo_surface_destroy (src_sf); hoff = b->rect.x (); voff = b->rect.y (); SmilTextBlock *tmp = b; b = b->next; delete tmp; } cairo_destroy (cr_txt); // update bounds rect s->bounds = matrix.toUser (IRect (scr.point, ISize (w, info.voffset))); txt->size = s->bounds.size; txt->updateBounds (false); // update coord. for painting below scr = matrix.toScreen (s->bounds); } } IRect clip_rect = clip.intersect (scr); if (s->surface && !clip_rect.isEmpty ()) paint (&txt->transition, txt->media_opacity, s, scr.point, clip_rect); s->dirty = false; } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Imfl * imfl) { if (imfl->surface ()) { cairo_save (cr); Matrix m = matrix; IRect scr = matrix.toScreen (SRect (0, 0, imfl->rp_surface->bounds.size)); int w = scr.width (); int h = scr.height (); cairo_rectangle (cr, scr.x (), scr.y (), w, h); //cairo_clip (cr); cairo_translate (cr, scr.x (), scr.y ()); cairo_scale (cr, 1.0*w/(double)imfl->size.width, 1.0*h/(double)imfl->size.height); if (imfl->needs_scene_img) cairo_push_group (cr); for (NodePtr n = imfl->firstChild (); n; n = n->nextSibling ()) if (n->state >= Node::state_began && n->state < Node::state_deactivated) { RP::TimingsBase * tb = convertNode(n); switch (n->id) { case RP::id_node_viewchange: if (!(int)tb->srcw) tb->srcw = imfl->size.width; if (!(int)tb->srch) tb->srch = imfl->size.height; // fall through case RP::id_node_crossfade: case RP::id_node_fadein: case RP::id_node_fadeout: case RP::id_node_fill: case RP::id_node_wipe: if (!(int)tb->w) tb->w = imfl->size.width; if (!(int)tb->h) tb->h = imfl->size.height; n->accept (this); break; } } if (imfl->needs_scene_img) { cairo_pattern_t * pat = cairo_pop_group (cr); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_set_source (cr, pat); cairo_paint (cr); cairo_pattern_destroy (pat); } cairo_restore (cr); matrix = m; } } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fill * fi) { CAIRO_SET_SOURCE_RGB (cr, fi->color); if ((int)fi->w && (int)fi->h) { cairo_rectangle (cr, fi->x, fi->y, fi->w, fi->h); cairo_fill (cr); } } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fadein * fi) { if (fi->target && fi->target->id == RP::id_node_image) { RP::Image *img = convertNode (fi->target); ImageMedia *im = img && img->media_info ? static_cast (img->media_info->media) : NULL; if (im && img->surface ()) { Single sx = fi->srcx, sy = fi->srcy, sw = fi->srcw, sh = fi->srch; if (!(int)sw) sw = img->size.width; if (!(int)sh) sh = img->size.height; if ((int)fi->w && (int)fi->h && (int)sw && (int)sh) { if (!img->img_surface->surface) im->cached_img->copyImage (img->img_surface, img->size, cairo_surface); cairo_matrix_t matrix; cairo_matrix_init_identity (&matrix); float scalex = 1.0 * sw / fi->w; float scaley = 1.0 * sh / fi->h; cairo_matrix_scale (&matrix, scalex, scaley); cairo_matrix_translate (&matrix, 1.0*sx/scalex - (double)fi->x, 1.0*sy/scaley - (double)fi->y); cairo_save (cr); cairo_rectangle (cr, fi->x, fi->y, fi->w, fi->h); cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_pattern_set_matrix (pat, &matrix); cairo_set_source (cr, pat); cairo_clip (cr); cairo_paint_with_alpha (cr, 1.0 * fi->progress / 100); cairo_restore (cr); cairo_pattern_destroy (pat); } } } } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fadeout * fo) { if (fo->progress > 0) { CAIRO_SET_SOURCE_RGB (cr, fo->to_color); if ((int)fo->w && (int)fo->h) { cairo_save (cr); cairo_rectangle (cr, fo->x, fo->y, fo->w, fo->h); cairo_clip (cr); cairo_paint_with_alpha (cr, 1.0 * fo->progress / 100); cairo_restore (cr); } } } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Crossfade * cf) { if (cf->target && cf->target->id == RP::id_node_image) { RP::Image *img = convertNode (cf->target); ImageMedia *im = img && img->media_info ? static_cast (img->media_info->media) : NULL; if (im && img->surface ()) { Single sx = cf->srcx, sy = cf->srcy, sw = cf->srcw, sh = cf->srch; if (!(int)sw) sw = img->size.width; if (!(int)sh) sh = img->size.height; if ((int)cf->w && (int)cf->h && (int)sw && (int)sh) { if (!img->img_surface->surface) im->cached_img->copyImage (img->img_surface, img->size, cairo_surface); cairo_save (cr); cairo_matrix_t matrix; cairo_matrix_init_identity (&matrix); float scalex = 1.0 * sw / cf->w; float scaley = 1.0 * sh / cf->h; cairo_matrix_scale (&matrix, scalex, scaley); cairo_matrix_translate (&matrix, 1.0*sx/scalex - (double)cf->x, 1.0*sy/scaley - (double)cf->y); cairo_rectangle (cr, cf->x, cf->y, cf->w, cf->h); cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_pattern_set_matrix (pat, &matrix); cairo_set_source (cr, pat); cairo_clip (cr); cairo_paint_with_alpha (cr, 1.0 * cf->progress / 100); cairo_restore (cr); cairo_pattern_destroy (pat); } } } } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Wipe * wipe) { if (wipe->target && wipe->target->id == RP::id_node_image) { RP::Image *img = convertNode (wipe->target); ImageMedia *im = img && img->media_info ? static_cast (img->media_info->media) : NULL; if (im && img->surface ()) { Single x = wipe->x, y = wipe->y; Single tx = x, ty = y; Single w = wipe->w, h = wipe->h; Single sx = wipe->srcx, sy = wipe->srcy, sw = wipe->srcw, sh = wipe->srch; if (!(int)sw) sw = img->size.width; if (!(int)sh) sh = img->size.height; if (wipe->direction == RP::Wipe::dir_right) { Single dx = w * 1.0 * wipe->progress / 100; tx = x -w + dx; w = dx; } else if (wipe->direction == RP::Wipe::dir_left) { Single dx = w * 1.0 * wipe->progress / 100; tx = x + w - dx; x = tx; w = dx; } else if (wipe->direction == RP::Wipe::dir_down) { Single dy = h * 1.0 * wipe->progress / 100; ty = y - h + dy; h = dy; } else if (wipe->direction == RP::Wipe::dir_up) { Single dy = h * 1.0 * wipe->progress / 100; ty = y + h - dy; y = ty; h = dy; } if ((int)w && (int)h) { if (!img->img_surface->surface) im->cached_img->copyImage (img->img_surface, img->size, cairo_surface); cairo_matrix_t matrix; cairo_matrix_init_identity (&matrix); float scalex = 1.0 * sw / wipe->w; float scaley = 1.0 * sh / wipe->h; cairo_matrix_scale (&matrix, scalex, scaley); cairo_matrix_translate (&matrix, 1.0*sx/scalex - (double)tx, 1.0*sy/scaley - (double)ty); cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_pattern_set_matrix (pat, &matrix); cairo_set_source (cr, pat); cairo_rectangle (cr, x, y, w, h); cairo_fill (cr); cairo_pattern_destroy (pat); } } } } KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::ViewChange * vc) { if (vc->unfinished () || vc->progress < 100) { cairo_pattern_t * pat = cairo_pop_group (cr); // from imfl cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_push_group (cr); cairo_save (cr); cairo_set_source (cr, pat); cairo_paint (cr); if ((int)vc->w && (int)vc->h && (int)vc->srcw && (int)vc->srch) { cairo_matrix_t matrix; cairo_matrix_init_identity (&matrix); float scalex = 1.0 * vc->srcw / vc->w; float scaley = 1.0 * vc->srch / vc->h; cairo_matrix_scale (&matrix, scalex, scaley); cairo_matrix_translate (&matrix, 1.0*vc->srcx/scalex - (double)vc->x, 1.0*vc->srcy/scaley - (double)vc->y); cairo_pattern_set_matrix (pat, &matrix); cairo_set_source (cr, pat); cairo_rectangle (cr, vc->x, vc->y, vc->w, vc->h); cairo_fill (cr); } cairo_pattern_destroy (pat); cairo_restore (cr); } } #endif //----------------------------------------------------------------------------- namespace KMPlayer { class KMPLAYER_NO_EXPORT MouseVisitor : public Visitor { ViewArea *view_area; Matrix matrix; NodePtrW source; const MessageType event; int x, y; bool handled; bool bubble_up; bool deliverAndForward (Node *n, Surface *s, bool inside, bool deliver); void surfaceEvent (Node *mt, Surface *s); public: MouseVisitor (ViewArea *v, MessageType evt, Matrix m, int x, int y); KDE_NO_CDTOR_EXPORT ~MouseVisitor () {} using Visitor::visit; void visit (Node * n); void visit (Element *); void visit (SMIL::Smil *); void visit (SMIL::Layout *); void visit (SMIL::RegionBase *); void visit (SMIL::MediaType * n); void visit (SMIL::SmilText * n); void visit (SMIL::Anchor *); void visit (SMIL::Area *); QCursor cursor; }; } // namespace KDE_NO_CDTOR_EXPORT MouseVisitor::MouseVisitor (ViewArea *v, MessageType evt, Matrix m, int a, int b) : view_area (v), matrix (m), event (evt), x (a), y (b), handled (false), bubble_up (false) { } KDE_NO_EXPORT void MouseVisitor::visit (Node * n) { kDebug () << "Mouse event ignored for " << n->nodeName (); } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Smil *s) { if (s->active () && s->layout_node) s->layout_node->accept (this); } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Layout * layout) { if (layout->root_layout) layout->root_layout->accept (this); } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::RegionBase *region) { Surface *s = (Surface *) region->role (RoleDisplay); if (s) { SRect rect = s->bounds; IRect scr = matrix.toScreen (rect); int rx = scr.x(), ry = scr.y(), rw = scr.width(), rh = scr.height(); handled = false; bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh; if (!inside && (event == MsgEventClicked || !s->has_mouse)) return; if (event == MsgEventClicked && !s->virtual_size.isEmpty () && x > rx + rw - REGION_SCROLLBAR_WIDTH) { const int sbh = rh - REGION_SCROLLBAR_WIDTH; const int vy = s->virtual_size.height; const int knob_h = sbh * rh / vy; int knob_y = y - ry - 0.5 * knob_h; if (knob_y < 0) knob_y = 0; else if (knob_y + knob_h > sbh) knob_y = sbh - knob_h; s->y_scroll = vy * knob_y / sbh; view_area->scheduleRepaint (scr); return; } if (event == MsgEventClicked && !s->virtual_size.isEmpty () && y > ry + rh - REGION_SCROLLBAR_WIDTH) { const int sbw = rw - REGION_SCROLLBAR_WIDTH; const int vw = s->virtual_size.width; const int knob_w = sbw * rw / vw; int knob_x = x - rx - 0.5 * knob_w; if (knob_x < 0) knob_x = 0; else if (knob_x + knob_w > sbw) knob_x = sbw - knob_w; s->x_scroll = vw * knob_x / sbw; view_area->scheduleRepaint (scr); return; } NodePtrW src = source; source = region; Matrix m = matrix; matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0); matrix.transform (m); if (!s->virtual_size.isEmpty ()) matrix.translate (-s->x_scroll, -s->y_scroll); bubble_up = false; bool child_handled = false; if (inside || s->has_mouse) for (SurfacePtr c = s->firstChild (); c; c = c->nextSibling ()) { if (c->node && c->node->id == SMIL::id_node_region) { c->node->accept (this); child_handled |= handled; if (!source || !source->active ()) break; } else { break; } } child_handled &= !bubble_up; bubble_up = false; if (source && source->active ()) deliverAndForward (region, s, inside, !child_handled); handled = inside; matrix = m; source = src; } } static void followLink (SMIL::LinkingBase * link) { kDebug() << "link to " << link->href << " clicked"; if (link->href.startsWith ("#")) { SMIL::Smil * s = SMIL::Smil::findSmilNode (link); if (s) s->jump (link->href.mid (1)); else kError() << "In document jumps smil not found" << endl; } else { PlayListNotify *notify = link->document ()->notify_listener; if (notify && !link->target.isEmpty ()) { notify->openUrl(KUrl(link->href), link->target, QString()); } else { NodePtr n = link; for (NodePtr p = link->parentNode (); p; p = p->parentNode ()) { if (n->mrl () && n->mrl ()->opener == p) { p->setState (Node::state_deferred); p->mrl ()->setParam (Ids::attr_src, link->href, 0L); p->activate (); break; } n = p; } } } } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Anchor * anchor) { if (event == MsgEventPointerMoved) cursor.setShape (Qt::PointingHandCursor); else if (event == MsgEventClicked) followLink (anchor); } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Area * area) { NodePtr n = area->parentNode (); Surface *s = (Surface *) n->role (RoleDisplay); if (s) { SRect rect = s->bounds; IRect scr = matrix.toScreen (rect); int w = scr.width (), h = scr.height (); if (area->nr_coords > 1) { Single left = area->coords[0].size (rect.width ()); Single top = area->coords[1].size (rect.height ()); matrix.getXY (left, top); if (x < left || x > left + w || y < top || y > top + h) return; if (area->nr_coords > 3) { Single right = area->coords[2].size (rect.width ()); Single bottom = area->coords[3].size (rect.height ()); matrix.getXY (right, bottom); if (x > right || y > bottom) return; } } if (event == MsgEventPointerMoved) cursor.setShape (Qt::PointingHandCursor); else { ConnectionList *nl = nodeMessageReceivers (area, event); if (nl) for (Connection *c = nl->first(); c; c = nl->next ()) { if (c->connecter) c->connecter->accept (this); if (!source || !source->active ()) return; } if (event == MsgEventClicked && !area->href.isEmpty ()) followLink (area); } } } KDE_NO_EXPORT void MouseVisitor::visit (Element *elm) { Runtime *rt = (Runtime *) elm->role (RoleTiming); if (rt) { Posting mouse_event (source, event); rt->message (event, &mouse_event); } } bool MouseVisitor::deliverAndForward (Node *node, Surface *s, bool inside, bool deliver) { bool forward = deliver; MessageType user_event = event; if (event == MsgEventPointerMoved) { forward = true; // always pass move events if (inside && !s->has_mouse) { deliver = true; user_event = MsgEventPointerInBounds; } else if (!inside && s->has_mouse) { deliver = true; user_event = MsgEventPointerOutBounds; } else if (!inside) { return false; } else { deliver = false; } } s->has_mouse = inside; if (event != MsgEventPointerMoved && !inside) return false; NodePtrW node_save = node; if (forward) { ConnectionList *nl = nodeMessageReceivers (node, MsgSurfaceAttach); if (nl) { NodePtr node_save = source; source = node; for (Connection *c = nl->first(); c; c = nl->next ()) { if (c->connecter) c->connecter->accept (this); if (!source || !source->active ()) break; } source = node_save; } } if (!node_save || !node->active ()) return false; if (deliver) { Posting mouse_event (node, user_event); node->deliver (user_event, &mouse_event); } if (!node_save || !node->active ()) return false; return true; } void MouseVisitor::surfaceEvent (Node *node, Surface *s) { if (!s) return; if (s->node && s->node.ptr () != node) { s->node->accept (this); return; } SRect rect = s->bounds; IRect scr = matrix.toScreen (rect); int rx = scr.x(), ry = scr.y(), rw = scr.width(), rh = scr.height(); const bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh; const bool had_mouse = s->has_mouse; if (deliverAndForward (node, s, inside, true) && (inside || had_mouse) && s->firstChild () && s->firstChild ()->node) { Matrix m = matrix; matrix = Matrix (rect.x(), rect.y(), s->xscale, s->yscale); matrix.transform (m); s->firstChild ()->node->accept (this); matrix = m; } } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::MediaType *mt) { if (mt->sensitivity == SMIL::MediaType::sens_transparent) bubble_up = true; else surfaceEvent (mt, mt->surface ()); } KDE_NO_EXPORT void MouseVisitor::visit (SMIL::SmilText *st) { surfaceEvent (st, st->surface ()); } //----------------------------------------------------------------------------- namespace KMPlayer { class KMPLAYER_NO_EXPORT ViewerAreaPrivate { public: ViewerAreaPrivate (ViewArea *v) : m_view_area (v), backing_store (0), gc(0), screen(NULL), visual(NULL), width(0), height(0) {} ~ViewerAreaPrivate() { destroyBackingStore (); if (gc) { xcb_connection_t* connection = QX11Info::connection(); xcb_free_gc(connection, gc); } } void clearSurface (Surface *s) { #ifdef KMPLAYER_WITH_CAIRO if (s->surface) { cairo_surface_destroy (s->surface); s->surface = 0L; } destroyBackingStore (); #endif } void resizeSurface (Surface *s) { #ifdef KMPLAYER_WITH_CAIRO -#if QT_VERSION >= 0x050600 int w = (int)(m_view_area->width() * m_view_area->devicePixelRatioF()); int h = (int)(m_view_area->height() * m_view_area->devicePixelRatioF()); -#else - int w = m_view_area->width (); - int h = m_view_area->height (); -#endif if ((w != width || h != height) && s->surface) { clearSurface (s); width = w; height = h; } #endif } #ifdef KMPLAYER_WITH_CAIRO cairo_surface_t *createSurface (int w, int h) { xcb_connection_t* connection = QX11Info::connection(); destroyBackingStore (); xcb_screen_t* scr = screen_of_display(connection, QX11Info::appScreen()); backing_store = xcb_generate_id(connection); xcb_void_cookie_t cookie = xcb_create_pixmap_checked(connection, scr->root_depth, backing_store, m_view_area->winId(), w, h); xcb_generic_error_t* error = xcb_request_check(connection, cookie); if (error) { qDebug("failed to create pixmap"); return NULL; } return cairo_xcb_surface_create(connection, backing_store, visual_of_screen(connection, scr), w, h); } void swapBuffer (const IRect &sr, int dx, int dy) { xcb_connection_t* connection = QX11Info::connection(); if (!gc) { gc = xcb_generate_id(connection); uint32_t values[] = { XCB_GX_COPY, XCB_FILL_STYLE_SOLID, XCB_SUBWINDOW_MODE_CLIP_BY_CHILDREN, 0 }; xcb_create_gc(connection, gc, backing_store, XCB_GC_FUNCTION | XCB_GC_FILL_STYLE | XCB_GC_SUBWINDOW_MODE | XCB_GC_GRAPHICS_EXPOSURES, values); } xcb_copy_area(connection, backing_store, m_view_area->winId(), gc, sr.x(), sr.y(), dx, dy, sr.width (), sr.height ()); xcb_flush(connection); } #endif void destroyBackingStore () { #ifdef KMPLAYER_WITH_CAIRO if (backing_store) { xcb_connection_t* connection = QX11Info::connection(); xcb_free_pixmap(connection, backing_store); } #endif backing_store = 0; } xcb_screen_t *screen_of_display(xcb_connection_t* c, int num) { if (!screen) { xcb_screen_iterator_t iter; iter = xcb_setup_roots_iterator (xcb_get_setup (c)); for (; iter.rem; --num, xcb_screen_next (&iter)) if (num == 0) { screen = iter.data; break; } } return screen; } xcb_visualtype_t* visual_of_screen(xcb_connection_t* c, xcb_screen_t* screen) { if (!visual) { xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator (screen); for (; depth_iter.rem; xcb_depth_next (&depth_iter)) { xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator (depth_iter.data); for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) { if (screen->root_visual == visual_iter.data->visual_id) { visual = visual_iter.data; break; } } } } return visual; } ViewArea *m_view_area; xcb_drawable_t backing_store; xcb_gcontext_t gc; xcb_screen_t* screen; xcb_visualtype_t* visual; int width; int height; }; class KMPLAYER_NO_EXPORT RepaintUpdater { public: RepaintUpdater (Node *n, RepaintUpdater *nx) : node (n), next (nx) {} NodePtrW node; RepaintUpdater *next; }; } KDE_NO_CDTOR_EXPORT ViewArea::ViewArea (QWidget *, View * view, bool paint_bg) // : QWidget (parent, "kde_kmplayer_viewarea", WResizeNoErase | WRepaintNoErase), : //QWidget (parent), d (new ViewerAreaPrivate (this)), m_view (view), m_collection (new KActionCollection (this)), surface (new Surface (this)), m_mouse_invisible_timer (0), m_repaint_timer (0), m_restore_fullscreen_timer (0), m_fullscreen (false), m_minimal (false), m_updaters_enabled (true), m_paint_background (paint_bg) { if (!paint_bg) setAttribute (Qt::WA_NoSystemBackground, true); QPalette palette; palette.setColor (backgroundRole(), QColor (0, 0, 0)); setPalette (palette); setAcceptDrops (true); //new KAction (i18n ("Fullscreen"), KShortcut (Qt::Key_F), this, SLOT (accelActivated ()), m_collection, "view_fullscreen_toggle"); setMouseTracking (true); setFocusPolicy (Qt::ClickFocus); QCoreApplication::instance()->installNativeEventFilter(this); } KDE_NO_CDTOR_EXPORT ViewArea::~ViewArea () { delete d; } KDE_NO_EXPORT void ViewArea::stopTimers () { if (m_mouse_invisible_timer) { killTimer (m_mouse_invisible_timer); m_mouse_invisible_timer = 0; } if (m_repaint_timer) { killTimer (m_repaint_timer); m_repaint_timer = 0; } } KDE_NO_EXPORT void ViewArea::fullScreen () { stopTimers (); if (m_fullscreen) { setVisible(false); setWindowState(windowState() & ~Qt::WindowFullScreen); // reset if (!m_restore_fullscreen_timer) m_restore_fullscreen_timer = startTimer(25); for (int i = 0; i < m_collection->count (); ++i) m_collection->action (i)->setEnabled (false); m_view->controlPanel()->enableFullscreenButton(false); unsetCursor(); } else { m_topwindow_rect = topLevelWidget ()->geometry (); -#if QT_VERSION >= 0x050200 m_view->dockArea()->takeCentralWidget(); -#else - setParent (0L); -#endif move(qApp->desktop()->screenGeometry(this).topLeft()); setVisible(true); setWindowState( windowState() ^ Qt::WindowFullScreen ); // set for (int i = 0; i < m_collection->count (); ++i) m_collection->action (i)->setEnabled (true); m_view->controlPanel()->enableFullscreenButton(true); m_mouse_invisible_timer = startTimer(MOUSE_INVISIBLE_DELAY); } m_fullscreen = !m_fullscreen; m_view->controlPanel()->fullscreenAction->setChecked (m_fullscreen); d->clearSurface (surface.ptr ()); emit fullScreenChanged (); } void ViewArea::minimalMode () { m_minimal = !m_minimal; stopTimers (); m_mouse_invisible_timer = m_repaint_timer = 0; if (m_minimal) { m_view->setViewOnly (); m_view->setControlPanelMode (KMPlayer::View::CP_AutoHide); m_view->setNoInfoMessages (true); m_view->controlPanel()->enableFullscreenButton(true); } else { m_view->setControlPanelMode (KMPlayer::View::CP_Show); m_view->setNoInfoMessages (false); m_view->controlPanel()->enableFullscreenButton(false); } m_topwindow_rect = topLevelWidget ()->geometry (); } KDE_NO_EXPORT void ViewArea::accelActivated () { m_view->controlPanel()->fullscreenAction->trigger (); } KDE_NO_EXPORT void ViewArea::keyPressEvent (QKeyEvent *e) { if (surface->node) { QString txt = e->text (); if (!txt.isEmpty ()) surface->node->document ()->message (MsgAccessKey, (void *)(long) txt[0].unicode ()); } } KDE_NO_EXPORT void ViewArea::mousePressEvent (QMouseEvent * e) { -#if QT_VERSION >= 0x050600 int devicex = (int)(e->x() * devicePixelRatioF()); int devicey = (int)(e->y() * devicePixelRatioF()); -#else - int devicex = e->x(); - int devicey = e->y(); -#endif if (surface->node) { MouseVisitor visitor (this, MsgEventClicked, Matrix (surface->bounds.x (), surface->bounds.y (), surface->xscale, surface->yscale), devicex, devicey); surface->node->accept (&visitor); } } KDE_NO_EXPORT void ViewArea::mouseDoubleClickEvent (QMouseEvent *) { m_view->fullScreen (); // screensaver stuff } KDE_NO_EXPORT void ViewArea::mouseMoveEvent (QMouseEvent * e) { if (e->buttons () == Qt::NoButton) m_view->mouseMoved (e->x (), e->y ()); if (surface->node) { -#if QT_VERSION >= 0x050600 int devicex = (int)(e->x() * devicePixelRatioF()); int devicey = (int)(e->y() * devicePixelRatioF()); -#else - int devicex = e->x(); - int devicey = e->y(); -#endif MouseVisitor visitor (this, MsgEventPointerMoved, Matrix (surface->bounds.x (), surface->bounds.y (), surface->xscale, surface->yscale), devicex, devicey); surface->node->accept (&visitor); setCursor (visitor.cursor); } e->accept (); mouseMoved (); // for m_mouse_invisible_timer } KDE_NO_EXPORT void ViewArea::syncVisual () { -#if QT_VERSION >= 0x050600 pixel_device_ratio = devicePixelRatioF(); int w = (int)(width() * devicePixelRatioF()); int h = (int)(height() * devicePixelRatioF()); -#else - int w = width(); - int h = heigth(); -#endif IRect rect = m_repaint_rect.intersect (IRect (0, 0, w, h)); #ifdef KMPLAYER_WITH_CAIRO if (surface->node) { int ex = rect.x (); if (ex > 0) ex--; int ey = rect.y (); if (ey > 0) ey--; int ew = rect.width () + 2; int eh = rect.height () + 2; IRect swap_rect; cairo_surface_t *merge = NULL; cairo_pattern_t *pat = NULL; cairo_t *cr = NULL; if (!surface->surface) { surface->surface = d->createSurface(w, h); swap_rect = IRect (ex, ey, ew, eh); CairoPaintVisitor visitor (surface->surface, Matrix (surface->bounds.x(), surface->bounds.y(), surface->xscale, surface->yscale), swap_rect, palette ().color (backgroundRole ()), true); surface->node->accept (&visitor); m_update_rect = IRect (); } else if (!rect.isEmpty ()) { merge = cairo_surface_create_similar (surface->surface, CAIRO_CONTENT_COLOR, ew, eh); { CairoPaintVisitor visitor (merge, Matrix (surface->bounds.x()-ex, surface->bounds.y()-ey, surface->xscale, surface->yscale), IRect (0, 0, ew, eh), palette ().color (backgroundRole ()), true); surface->node->accept (&visitor); } cr = cairo_create (surface->surface); pat = cairo_pattern_create_for_surface (merge); cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE); cairo_matrix_t mat; cairo_matrix_init_translate (&mat, (int) -ex, (int) -ey); cairo_pattern_set_matrix (pat, &mat); cairo_set_source (cr, pat); //cairo_set_operator (cr, CAIRO_OPERATOR_ADD); cairo_rectangle (cr, ex, ey, ew, eh); //cairo_fill (cr); cairo_clip (cr); cairo_paint_with_alpha (cr, .8); swap_rect = IRect (ex, ey, ew, eh).unite (m_update_rect); m_update_rect = IRect (ex, ey, ew, eh); } else { swap_rect = m_update_rect; m_update_rect = IRect (); } d->swapBuffer (swap_rect, swap_rect.x (), swap_rect.y ()); if (merge) { cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_rectangle (cr, ex, ey, ew, eh); cairo_fill (cr); cairo_destroy (cr); cairo_pattern_destroy (pat); cairo_surface_destroy (merge); } cairo_surface_flush (surface->surface); } else #endif { m_update_rect = IRect (); -#if QT_VERSION >= 0x050600 repaint(QRect(rect.x() / devicePixelRatioF(), rect.y() / devicePixelRatioF(), rect.width() / devicePixelRatioF(), rect.height() / devicePixelRatioF())); -#else - repaint (QRect(rect.x(), rect.y(), rect.width(), rect.height())); -#endif } } KDE_NO_EXPORT void ViewArea::paintEvent (QPaintEvent * pe) { #ifdef KMPLAYER_WITH_CAIRO if (surface->node) { -#if QT_VERSION >= 0x050600 int x = (int)(pe->rect().x() * devicePixelRatioF()); int y = (int)(pe->rect().y() * devicePixelRatioF()); int w = (int)(pe->rect().width() * devicePixelRatioF()); int h = (int)(pe->rect().height() * devicePixelRatioF()); -#else - int x = pe->rect().x(); - int y = pe->rect().y(); - int w = pe->rect().width(); - int h = pe->rect().height(); -#endif scheduleRepaint(IRect(x, y, w, h)); } else #endif if (m_fullscreen || m_paint_background) { QPainter p (this); p.fillRect (pe->rect (), QBrush (palette ().color (backgroundRole ()))); p.end (); } } QPaintEngine *ViewArea::paintEngine () const { #ifdef KMPLAYER_WITH_CAIRO if (surface->node) return NULL; else #endif return QWidget::paintEngine (); } KDE_NO_EXPORT void ViewArea::scale (int) { resizeEvent (0L); } KDE_NO_EXPORT void ViewArea::updateSurfaceBounds () { -#if QT_VERSION >= 0x050600 int devicew = (int)(width() * devicePixelRatioF()); int deviceh = (int)(height() * devicePixelRatioF()); -#else - int devicew = width, deviceh = height() -#endif Single x, y, w = devicew, h = deviceh; h -= m_view->statusBarHeight (); h -= m_view->controlPanel ()->isVisible () && !m_fullscreen ? (m_view->controlPanelMode () == View::CP_Only ? h : (Single) m_view->controlPanel()->maximumSize ().height ()) : Single (0); int scale = m_view->controlPanel ()->scale_slider->sliderPosition (); if (scale != 100) { int nw = w * 1.0 * scale / 100; int nh = h * 1.0 * scale / 100; x += (w - nw) / 2; y += (h - nh) / 2; w = nw; h = nh; } if (surface->node) { d->resizeSurface (surface.ptr ()); surface->resize (SRect (x, y, w, h)); surface->node->message (MsgSurfaceBoundsUpdate, (void *) true); } scheduleRepaint (IRect (0, 0, devicew, deviceh)); } KDE_NO_EXPORT void ViewArea::resizeEvent (QResizeEvent *) { if (!m_view->controlPanel ()) return; Single x, y, w = width (), h = height (); Single hsb = m_view->statusBarHeight (); int hcp = m_view->controlPanel ()->isVisible () ? (m_view->controlPanelMode () == View::CP_Only ? h-hsb : (Single) m_view->controlPanel()->maximumSize ().height ()) : Single (0); // move controlpanel over video when autohiding and playing bool auto_hide = m_view->controlPanelMode () == View::CP_AutoHide; h -= Single (auto_hide ? 0 : hcp) - hsb; // now scale the regions and check if video region is already sized updateSurfaceBounds (); // finally resize controlpanel and video widget if (m_view->controlPanel ()->isVisible ()) m_view->controlPanel ()->setGeometry (0, h-(auto_hide ? hcp:0), w, hcp); if (m_view->statusBar ()->isVisible ()) m_view->statusBar ()->setGeometry (0, h-hsb, w, hsb); int scale = m_view->controlPanel ()->scale_slider->sliderPosition (); Single ws = w * scale / 100; Single hs = h * scale / 100; x += (w - ws) / 2; y += (h - hs) / 2; m_view->console ()->setGeometry (0, 0, w, h); m_view->picture ()->setGeometry (0, 0, w, h); if (!surface->node && video_widgets.size () == 1) { -#if QT_VERSION >= 0x050600 x *= devicePixelRatioF(); y *= devicePixelRatioF(); ws *= devicePixelRatioF(); hs *= devicePixelRatioF(); -#endif video_widgets.first ()->setGeometry (IRect (x, y, ws, hs)); } } KDE_NO_EXPORT Surface *ViewArea::getSurface (Mrl *mrl) { surface->clear (); surface->node = mrl; kDebug() << mrl; //m_view->viewer()->resetBackgroundColor (); if (mrl) { updateSurfaceBounds (); #ifdef KMPLAYER_WITH_CAIRO setAttribute (Qt::WA_OpaquePaintEvent, true); setAttribute (Qt::WA_PaintOnScreen, true); #endif return surface.ptr (); } else { #ifdef KMPLAYER_WITH_CAIRO setAttribute (Qt::WA_OpaquePaintEvent, false); setAttribute (Qt::WA_PaintOnScreen, false); d->clearSurface (surface.ptr ()); #endif } -#if QT_VERSION >= 0x050600 int devicew = (int)(width() * devicePixelRatioF()); int deviceh = (int)(height() * devicePixelRatioF()); scheduleRepaint (IRect (0, 0, devicew, deviceh)); -#else - scheduleRepaint (IRect (0, 0, width (), height ())); -#endif return 0L; } KDE_NO_EXPORT void ViewArea::showEvent (QShowEvent *) { resizeEvent (0L); } KDE_NO_EXPORT void ViewArea::dropEvent (QDropEvent * de) { m_view->dropEvent (de); } KDE_NO_EXPORT void ViewArea::dragEnterEvent (QDragEnterEvent* dee) { m_view->dragEnterEvent (dee); } KDE_NO_EXPORT void ViewArea::contextMenuEvent (QContextMenuEvent * e) { m_view->controlPanel ()->popupMenu->exec (e->globalPos ()); } KDE_NO_EXPORT void ViewArea::mouseMoved () { if (m_fullscreen) { if (m_mouse_invisible_timer) killTimer (m_mouse_invisible_timer); unsetCursor (); m_mouse_invisible_timer = startTimer (MOUSE_INVISIBLE_DELAY); } } KDE_NO_EXPORT void ViewArea::scheduleRepaint (const IRect &rect) { if (m_repaint_timer) { m_repaint_rect = m_repaint_rect.unite (rect); } else { m_repaint_rect = rect; m_repaint_timer = startTimer (25); } } KDE_NO_EXPORT ConnectionList *ViewArea::updaters () { if (!m_repaint_timer) m_repaint_timer = startTimer (25); return &m_updaters; } KDE_NO_EXPORT void ViewArea::enableUpdaters (bool enable, unsigned int skip) { m_updaters_enabled = enable; Connection *connect = m_updaters.first (); if (enable && connect) { UpdateEvent event (connect->connecter->document (), skip); for (; connect; connect = m_updaters.next ()) if (connect->connecter) connect->connecter->message (MsgSurfaceUpdate, &event); if (!m_repaint_timer) m_repaint_timer = startTimer (25); } else if (!enable && m_repaint_timer && m_repaint_rect.isEmpty () && m_update_rect.isEmpty ()) { killTimer (m_repaint_timer); m_repaint_timer = 0; } } KDE_NO_EXPORT void ViewArea::timerEvent (QTimerEvent * e) { if (e->timerId () == m_mouse_invisible_timer) { killTimer (m_mouse_invisible_timer); m_mouse_invisible_timer = 0; if (m_fullscreen) setCursor (QCursor (Qt::BlankCursor)); } else if (e->timerId () == m_repaint_timer) { Connection *connect = m_updaters.first (); int count = 0; if (m_updaters_enabled && connect) { UpdateEvent event (connect->connecter->document (), 0); for (; connect; count++, connect = m_updaters.next ()) if (connect->connecter) connect->connecter->message (MsgSurfaceUpdate, &event); } //repaint (m_repaint_rect, false); if (!m_repaint_rect.isEmpty () || !m_update_rect.isEmpty ()) { syncVisual (); m_repaint_rect = IRect (); } if (m_update_rect.isEmpty () && (!m_updaters_enabled || !m_updaters.first ())) { killTimer (m_repaint_timer); m_repaint_timer = 0; } } else if (e->timerId () == m_restore_fullscreen_timer) { xcb_connection_t* connection = QX11Info::connection(); xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(connection, winId()); xcb_get_window_attributes_reply_t* attrs = xcb_get_window_attributes_reply(connection, cookie, NULL); if (attrs->map_state == XCB_MAP_STATE_UNMAPPED) { m_view->dockArea ()->setCentralWidget (this); killTimer(m_restore_fullscreen_timer); m_restore_fullscreen_timer = 0; } free(attrs); } else { kError () << "unknown timer " << e->timerId () << " " << m_repaint_timer << endl; killTimer (e->timerId ()); } } KDE_NO_EXPORT void ViewArea::closeEvent (QCloseEvent * e) { //kDebug () << "closeEvent"; if (m_fullscreen) { m_view->fullScreen(); if (!m_view->topLevelWidget ()->isVisible ()) m_view->topLevelWidget ()->setVisible (true); e->ignore (); } else QWidget::closeEvent (e); } IViewer *ViewArea::createVideoWidget () { VideoOutput *viewer = new VideoOutput (this, m_view); video_widgets.push_back (viewer); viewer->setGeometry (IRect (-60, -60, 50, 50)); viewer->setVisible (true); m_view->controlPanel ()->raise (); return viewer; } void ViewArea::destroyVideoWidget (IViewer *widget) { int i = video_widgets.indexOf(widget); if (i >= 0) { IViewer *viewer = widget; delete viewer; video_widgets.removeAt(i); } else { kWarning () << "destroyVideoWidget widget not found" << endl; } } void ViewArea::setVideoWidgetVisible (bool show) { const VideoWidgetList::iterator e = video_widgets.end (); for (VideoWidgetList::iterator it = video_widgets.begin (); it != e; ++it) static_cast (*it)->setVisible (show); } static void setXSelectInput(WId wid, uint32_t mask) { xcb_connection_t* connection = QX11Info::connection(); const uint32_t values[] = { mask }; xcb_change_window_attributes(connection, wid, XCB_CW_EVENT_MASK, values); xcb_query_tree_cookie_t biscuit = xcb_query_tree(connection, wid); xcb_query_tree_reply_t *reply = xcb_query_tree_reply(connection, biscuit, NULL); if (reply) { xcb_window_t *chlds = xcb_query_tree_children(reply); for (int i = 0; i < xcb_query_tree_children_length(reply); i++) setXSelectInput(chlds[i], mask); free(reply); } else { qDebug("failed to get x children"); } } bool ViewArea::nativeEventFilter(const QByteArray& eventType, void * message, long *result) { if (eventType != "xcb_generic_event_t") return false; xcb_generic_event_t* event = (xcb_generic_event_t*)message; switch (event->response_type & ~0x80) { case XCB_UNMAP_NOTIFY: { xcb_unmap_notify_event_t* ev = (xcb_unmap_notify_event_t*)event; if (ev->event != ev->window) { const VideoWidgetList::iterator e = video_widgets.end (); for (VideoWidgetList::iterator i=video_widgets.begin(); i != e; ++i) { if (ev->event == (*i)->ownHandle()) { (*i)->embedded(0); break; } } } break; } case XCB_MAP_NOTIFY: { xcb_map_notify_event_t* ev = (xcb_map_notify_event_t*)event; if (!ev->override_redirect && ev->event != ev->window) { xcb_connection_t* connection = QX11Info::connection(); const VideoWidgetList::iterator e = video_widgets.end (); for (VideoWidgetList::iterator i=video_widgets.begin(); i != e; ++i) { if (ev->event == (*i)->ownHandle()) { (*i)->embedded(ev->window); return false; } xcb_window_t p = ev->event; xcb_window_t w = ev->window; xcb_window_t v = (*i)->clientHandle (); xcb_window_t va = winId (); xcb_window_t root = 0; while (p != v) { xcb_query_tree_cookie_t cookie = xcb_query_tree(connection, w); xcb_query_tree_reply_t *reply = xcb_query_tree_reply(connection, cookie, NULL); if (reply) { p = reply->parent; root = reply->root; free(reply); } else { qDebug("failed to get x parent"); break; } if (p == va || p == v || p == root) break; w = p; } if (p == v) { setXSelectInput (ev->window, static_cast (*i)->inputMask ()); break; } } } break; } case XCB_MOTION_NOTIFY: { xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event; if (m_view->controlPanelMode () == View::CP_AutoHide) { const VideoWidgetList::iterator e = video_widgets.end (); for (VideoWidgetList::iterator i=video_widgets.begin(); i != e; ++i) { QPoint p = mapToGlobal (QPoint (0, 0)); int x = ev->root_x - p.x (); int y = ev->root_y - p.y (); -#if QT_VERSION >= 0x050600 m_view->mouseMoved(x / devicePixelRatioF(), y / devicePixelRatioF()); int devicew = (int)(width() * devicePixelRatioF()); int deviceh = (int)(height() * devicePixelRatioF()); -#else - m_view->mouseMoved (x, y); - int devicew = width(); - int deviceh = height(); -#endif if (x > 0 && x < devicew && y > 0 && y < deviceh) mouseMoved (); } } break; } case XCB_KEY_PRESS: { xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event; const VideoWidgetList::iterator e = video_widgets.end (); for (VideoWidgetList::iterator i=video_widgets.begin(); i != e; ++i) if ((*i)->clientHandle () == ev->event && static_cast (*i)->inputMask() & XCB_EVENT_MASK_KEY_PRESS) { if (ev->detail == 41 /*FIXME 'f'*/) m_view->fullScreen (); break; } break; } default: break; } return false; } //---------------------------------------------------------------------- KDE_NO_CDTOR_EXPORT VideoOutput::VideoOutput (QWidget *parent, View * view) : QX11EmbedContainer (parent), m_plain_window(0), m_client_window(0), resized_timer(0), m_bgcolor (0), m_aspect (0.0), m_view (view) { setAcceptDrops (true); connect (view->viewArea (), SIGNAL (fullScreenChanged ()), this, SLOT (fullScreenChanged ())); kDebug() << "VideoOutput::VideoOutput" << endl; setMonitoring (MonitorAll); setAttribute (Qt::WA_NoSystemBackground, true); xcb_connection_t* connection = QX11Info::connection(); xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(connection, winId()); xcb_get_window_attributes_reply_t* attrs = xcb_get_window_attributes_reply(connection, cookie, NULL); if (!(attrs->your_event_mask & XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY)) setXSelectInput(winId(), attrs->your_event_mask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY); free(attrs); //setProtocol (QXEmbed::XPLAIN); } KDE_NO_CDTOR_EXPORT VideoOutput::~VideoOutput () { kDebug() << "VideoOutput::~VideoOutput" << endl; if (m_plain_window) { xcb_connection_t* connection = QX11Info::connection(); xcb_destroy_window(connection, m_plain_window); xcb_flush(connection); m_plain_window = 0; } } void VideoOutput::useIndirectWidget (bool inderect) { kDebug () << "setIntermediateWindow " << !!m_plain_window << "->" << inderect; if (!clientWinId () || !!m_plain_window != inderect) { xcb_connection_t* connection = QX11Info::connection(); if (inderect) { if (!m_plain_window) { xcb_screen_t* scr = m_view->viewArea()->d->screen_of_display(connection, QX11Info::appScreen()); m_plain_window = xcb_generate_id(connection); uint32_t values[] = { scr->black_pixel, m_input_mask }; -#if QT_VERSION >= 0x050600 int devicew = (int)(width() * devicePixelRatioF()); int deviceh = (int)(height() * devicePixelRatioF()); -#else - int devicew = width(); - int deviceh = height(); -#endif xcb_create_window(connection, XCB_COPY_FROM_PARENT, m_plain_window, winId(), 0, 0, devicew, deviceh, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, values); xcb_map_window(connection, m_plain_window); xcb_flush(connection); //XSync (QX11Info::display (), false); //embedClient (m_plain_window); } //XClearWindow (QX11Info::display(), m_plain_window); } else { if (m_plain_window) { xcb_unmap_window(connection, m_plain_window); discardClient (); xcb_destroy_window(connection, m_plain_window); xcb_flush(connection); m_plain_window = 0; //XSync (QX11Info::display (), false); } } } } KDE_NO_EXPORT void VideoOutput::embedded(WindowId handle) { kDebug () << "windowChanged " << (int)clientWinId (); m_client_window = handle; if (clientWinId () && !resized_timer) resized_timer = startTimer (50); if (clientWinId()) setXSelectInput (clientWinId (), m_input_mask); } KDE_NO_EXPORT void VideoOutput::resizeEvent (QResizeEvent *) { if (clientWinId () && !resized_timer) resized_timer = startTimer (50); } KDE_NO_EXPORT void VideoOutput::timerEvent (QTimerEvent *e) { if (e->timerId () == resized_timer) { killTimer (resized_timer); resized_timer = 0; if (clientWinId ()) { xcb_connection_t* connection = QX11Info::connection(); -#if QT_VERSION >= 0x050600 uint32_t devicew = (uint32_t)(width() * devicePixelRatioF()); uint32_t deviceh = (uint32_t)(height() * devicePixelRatioF()); -#else - uint32_t devicew = width(); - uint32_t deviceh = height(); -#endif uint32_t values[] = { 0, 0, devicew, deviceh }; xcb_configure_window(connection, clientWinId(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); xcb_flush(connection); } } } WindowId VideoOutput::windowHandle () { //return m_plain_window ? clientWinId () : winId (); return m_plain_window ? m_plain_window : winId (); } WindowId VideoOutput::ownHandle () { return winId (); } WindowId VideoOutput::clientHandle () { return clientWinId (); } void VideoOutput::setGeometry (const IRect &rect) { -#if QT_VERSION >= 0x050600 int x = (int)(rect.x() / devicePixelRatioF()); int y = (int)(rect.y() / devicePixelRatioF()); int w = (int)(rect.width() / devicePixelRatioF()); int h = (int)(rect.height() / devicePixelRatioF()); -#else - int x = rect.x (), y = rect.y (), w = rect.width (), h = rect.height (); -#endif if (m_view->keepSizeRatio ()) { // scale video widget inside region int hfw = heightForWidth (w); if (hfw > 0) { if (hfw > h) { int old_w = w; w = int ((1.0 * h * w)/(1.0 * hfw)); x += (old_w - w) / 2; } else { y += (h - hfw) / 2; h = hfw; } } } setGeometry (x, y, w, h); setVisible (true); } void VideoOutput::setAspect (float a) { m_aspect = a; QRect r = geometry (); -#if QT_VERSION >= 0x050600 int x = (int)(r.x() * devicePixelRatioF()); int y = (int)(r.y() * devicePixelRatioF()); int w = (int)(r.width() * devicePixelRatioF()); int h = (int)(r.height() * devicePixelRatioF()); -#else - int x = r.x(); - int y = r.y(); - int w = r.width(); - int h = r.height(); -#endif m_view->viewArea()->scheduleRepaint(IRect(x, y, w, h)); } KDE_NO_EXPORT void VideoOutput::map () { setVisible (true); } KDE_NO_EXPORT void VideoOutput::unmap () { setVisible (false); } KDE_NO_EXPORT void VideoOutput::setMonitoring (Monitor m) { m_input_mask = //KeyPressMask | KeyReleaseMask | //EnterWindowMask | LeaveWindowMask | //FocusChangeMask | XCB_EVENT_MASK_EXPOSURE | //StructureNotifyMask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; if (m & MonitorMouse) m_input_mask |= XCB_EVENT_MASK_POINTER_MOTION; if (m & MonitorKey) m_input_mask |= XCB_EVENT_MASK_KEY_PRESS; if (clientWinId ()) setXSelectInput (clientWinId (), m_input_mask); } KDE_NO_EXPORT void VideoOutput::fullScreenChanged () { if (!(m_input_mask & XCB_EVENT_MASK_KEY_PRESS)) { // FIXME: store monitor when needed if (m_view->isFullScreen ()) m_input_mask |= XCB_EVENT_MASK_POINTER_MOTION; else m_input_mask &= ~XCB_EVENT_MASK_POINTER_MOTION; } if (clientWinId ()) setXSelectInput (clientWinId (), m_input_mask); } KDE_NO_EXPORT int VideoOutput::heightForWidth (int w) const { if (m_aspect <= 0.01) return 0; return int (w/m_aspect); } KDE_NO_EXPORT void VideoOutput::dropEvent (QDropEvent * de) { m_view->dropEvent (de); } KDE_NO_EXPORT void VideoOutput::dragEnterEvent (QDragEnterEvent* dee) { m_view->dragEnterEvent (dee); } KDE_NO_EXPORT void VideoOutput::contextMenuEvent (QContextMenuEvent * e) { m_view->controlPanel ()->popupMenu->exec (e->globalPos ()); } KDE_NO_EXPORT void VideoOutput::setBackgroundColor (const QColor & c) { if (m_bgcolor != c.rgb ()) { m_bgcolor = c.rgb (); setCurrentBackgroundColor (c); } } KDE_NO_EXPORT void VideoOutput::resetBackgroundColor () { setCurrentBackgroundColor (m_bgcolor); } KDE_NO_EXPORT void VideoOutput::setCurrentBackgroundColor (const QColor & c) { QPalette palette; palette.setColor (backgroundRole(), c); setPalette (palette); if (clientWinId()) { xcb_connection_t* connection = QX11Info::connection(); const uint32_t values[] = { c.rgb() }; xcb_change_window_attributes(connection, clientWinId(), XCB_CW_BACK_PIXEL, values); xcb_flush(connection); } } #include "viewarea.moc"