diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-17 00:54:13 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-17 00:54:13 +0000 |
commit | 092be7678b67552cb3161fe162242bf8d3aeed2f (patch) | |
tree | be0693f45b101252c370e40f6e84da2cd7a52f75 /src | |
download | kmplayer-092be7678b67552cb3161fe162242bf8d3aeed2f.tar.gz kmplayer-092be7678b67552cb3161fe162242bf8d3aeed2f.zip |
Added old abandoned KDE3 version of kmplayer
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kmplayer@1091557 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src')
86 files changed, 44010 insertions, 0 deletions
diff --git a/src/DESIGN.txt b/src/DESIGN.txt new file mode 100644 index 0000000..e0e3a31 --- /dev/null +++ b/src/DESIGN.txt @@ -0,0 +1,38 @@ +The core of kmplayer is in kmplayerpartbase.x. PartBase keeps +the list of Source objects (dvd/vcd/url/..) and Process objects +(mplayer/xine/gst/xv), controls the View or respond to its signals. Both +application as kpart (for plugin) have one PartBase. However, in case of +plugin for khtml, it's possible one PartBase controls multible View +objects (see tests/controls.html). + +The View is the parent of ViewArea, PlayList and InfoWindow. ViewArea is +the parent of Viewer (the output for the backend players) and +ControlPanel. +In case of smil animations, the Viewer widget can be hidden or made +smaller so ViewArea background is where the rendering is done. +Classes in kmplayerplaylist.x are actually base for the XML playlist +formats (smil/asx/rss/..). + +There is always one Source object active. A Source object sets up the +interface to the user as far possible, handling playlists and launching +backends. This is not fully worked out yet, eg. URLSource should be able +to launch multible backends for smil. Which probably means that PartBase +should have a list of Process factories and Source objects a list of +running Process objects. + +Backends are instances of Process and should be simple, just passing +data from/to external processes. A Recorder object is also a Process. +Though for mplayer, there is quite some code for output parsing. + +The XML classes and parser provide a quick way for storing any XML file +in the playlist. Tree nodes build the tree themselves and recognized +multimedia elements more or less play the playlist themselves too. +The parser is build to recover from all kinds of typos. This is because +ASX is quite often full of XML errors that made other parsers give up, +eg. I've seen something like "<Title>Laurel & Hardy< / title>". + +KMPlayerPart and KMPlayerApp are classes that use the above for plugin +and application. + +Finally there is also a Settings class for general usage and for +launching the configure dialog. diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c481b8d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,80 @@ +AM_CPPFLAGS= -I$(kde_includes)/kio $(CFLAGS_GST) $(all_includes) $(LIBCAIRO_CFLAGS) $(LIBNSPR_CFLAGS) $(LIBDBUS_CFLAGS) + +METASOURCES= AUTO + +lib_LTLIBRARIES= libkmplayercommon.la + +libkmplayercommon_la_SOURCES = viewarea.cpp kmplayerview.cpp playlistview.cpp kmplayercontrolpanel.cpp kmplayerconfig.cpp pref.cpp kmplayerprocess.cpp kmplayer_callback.skel kmplayer_backend.stub kmplayerpartbase.cpp kmplayerplaylist.cpp kmplayer_asx.cpp kmplayer_smil.cpp kmplayer_rp.cpp kmplayer_rss.cpp kmplayer_atom.cpp kmplayer_xspf.cpp triestring.cpp kmplayerpartbase.skel +libkmplayercommon_la_LDFLAGS = -avoid-version $(all_libraries) +libkmplayercommon_la_LIBADD = -lkmediaplayer $(LIB_KPARTS) $(LIB_KUTILS) $(LIB_EXPAT) -lm $(LIBCAIRO_LIBS) $(LIBQTDBUS) + +if include_koffice_support +kofficeplugin_lib= libkmplayerkofficepart.la +SERVICES_KOFFICE = kmplayer_koffice.desktop +endif + +kde_module_LTLIBRARIES= libkmplayerpart.la $(kofficeplugin_lib) + +libkmplayerpart_la_SOURCES= kmplayer_part.cpp +libkmplayerpart_la_LDFLAGS= -avoid-version $(all_libraries) $(KDE_RPATH) +libkmplayerpart_la_LIBADD= libkmplayercommon.la + +libkmplayerkofficepart_la_SOURCES=kmplayer_koffice_part.cpp +libkmplayerkofficepart_la_LDFLAGS= -avoid-version $(all_libraries) $(KDE_RPATH) +libkmplayerkofficepart_la_LIBADD= libkmplayercommon.la $(LIB_KOFFICE) + +kdeinit_LTLIBRARIES=kmplayer.la +kmplayer_la_SOURCES= main.cpp kmplayerapp.cpp kmplayertvsource.cpp kmplayerbroadcast.cpp kmplayervdr.cpp +kmplayer_la_LIBADD= libkmplayercommon.la +kmplayer_la_LDFLAGS= -module $(KDE_PLUGIN) + +EXTRA_PROGRAMS = kxineplayer kxvplayer kgstplayer +if include_kxineplayer +kxineplayer_app = kxineplayer +endif +if include_kgstplayer +kgstplayer_app = kgstplayer +endif +if include_knpplayer +knpplayer_app = knpplayer +endif + +bin_PROGRAMS= $(kxineplayer_app) kxvplayer $(kgstplayer_app) $(knpplayer_app) + +noinst_LTLIBRARIES = libkmplayerbackend.la +libkmplayerbackend_la_SOURCES = kmplayer_backend.skel kmplayer_callback.stub + +kxineplayer_LDADD= libkmplayerbackend.la $(LIB_XINE) -lDCOP +kxineplayer_CFLAGS= $(CFLAGS_XINE) +kxineplayer_LDFLAGS= $(all_libraries) $(KDE_RPATH) +kxineplayer_SOURCES= xineplayer.cpp + +kxvplayer_LDADD= libkmplayerbackend.la -lDCOP -lXv +kxvplayer_LDFLAGS= $(all_libraries) $(KDE_RPATH) +kxvplayer_SOURCES= xvplayer.cpp + +kgstplayer_LDADD= libkmplayerbackend.la $(LIB_GST) $(LIB_GST_PLUGINS) -lgstinterfaces-0.10 -lDCOP +kgstplayer_LDFLAGS= $(all_libraries) $(KDE_RPATH) +kgstplayer_SOURCES= gstplayer.cpp + +knpplayer_LDADD= $(LIBNSPR_LIBS) +knpplayer_SOURCES= npplayer.c + +xdg_apps_DATA = kmplayer.desktop + +kde_services_DATA = kmplayer_part.desktop $(SERVICES_KOFFICE) + +rc_DATA = kmplayerui.rc kmplayerpartui.rc +rcdir = $(kde_datadir)/kmplayer + +conf_DATA = kmplayerrc +confdir = $(kde_confdir) + +appsdatadir=$(kde_datadir)/kmplayer +appsdata_DATA= bookmarks.xml pluginsinfo noise.gif + +dummy.cpp: + echo > dummy.cpp + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kmplayer.pot diff --git a/src/bookmarks.xml b/src/bookmarks.xml new file mode 100644 index 0000000..bf4c89a --- /dev/null +++ b/src/bookmarks.xml @@ -0,0 +1,670 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE xbel> +<xbel folded="yes" > + <folder folded="yes" icon="bookmark_folder" > + <title>South America</title> + <folder folded="yes" icon="bookmark_folder" > + <title>Brazil</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveBR_nb.ram" > + <title>Bloomberg TV Brazil</title> + </bookmark> + </folder> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>Asia</title> + <folder folded="yes" icon="bookmark_folder" > + <title>TV</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveAS_nb.ram" > + <title>Bloomberg TV Asia-Pacific</title> + </bookmark> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveJA_nb.ram" > + <title>Bloomberg TV Japan</title> + </bookmark> + </folder> + </folder> + <folder folded="no" icon="bookmark_folder" > + <title>Europe</title> + <folder folded="no" icon="bookmark_folder" > + <title>belgium</title> + <folder folded="no" > + <title>flanders</title> + <bookmark icon="www" href="http://mp3.streampower.be/radio1-high.mp3" > + <title>Radio 1</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/sporza-high.mp3" > + <title>Sporza</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/ra2ant-high.mp3" > + <title>Radio 2 Antwerpen</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/ra2vlb-high.mp3" > + <title>Radio 2 Vlaams-Brabant</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/ra2lim-high.mp3" > + <title>Radio 2 Limburg</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/ra2ovl-high.mp3" > + <title>Radio 2 Oost-Vlaanderen</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/ra2wvl-high.mp3" > + <title>Radio 2 West-Vlaanderen</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/klara-high.mp3" > + <title>Klara</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/klaracontinuo-high.mp3" > + <title>Klara Continuo</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/stubru-high.mp3" > + <title>Studio Brussel</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/donna-high.mp3" > + <title>Donna</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/donnahitbits-high.mp3" > + <title>Donna Hitbits</title> + </bookmark> + <bookmark icon="www" href="http://mp3.streampower.be/rvi-high.mp3" > + <title>RVI</title> + </bookmark> + <bookmark icon="www" href="http://stream.urgent.fm/high.ogg" > + <title>Urgent.fm</title> + </bookmark> + <bookmark icon="www" href="http://www.beoneradio.be/modules/desktop/streaming/pls.aspx?mid=84" > + <title>Be One</title> + </bookmark> + <bookmark icon="www" href="http://mediaserver02.cybernet.be/contactnl" > + <title>Radio Contact</title> + </bookmark> + <bookmark icon="www" href="http://wm.streampower.be/qmusic_ahi" > + <title>Q-Music</title> + </bookmark> + <bookmark icon="www" href="http://www.topradio.be/new/website/topradioHigh.asx" > + <title>Topradio</title> + </bookmark> + <bookmark icon="www" href="http://www.4fm.be/streams/high.asx" > + <title>4fm</title> + </bookmark> + </folder> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>czech republic</title> + <folder folded="yes" icon="bookmark_folder" > + <title>radio valc</title> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc-5.asx" > + <title>radio valc live</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc1-2.asx" > + <title>radio valc 1 gold</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc2-2.asx" > + <title>radio valc 2 country</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc3-2.asx" > + <title>radio valc 3 hit</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc4-2.asx" > + <title>radio valc 4 rock</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc5-2.asx" > + <title>radio valc 5 classic</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc6-2.asx" > + <title>radio valc 6 valcarka</title> + </bookmark> + <bookmark icon="sound" href="http://www.radiovalc.cz/asx/valc7-2.asx" > + <title>radio valc 7 folk</title> + </bookmark> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>cesky rozhlas</title> + <bookmark icon="sound" href="mms://netshow4.live.cz/cro1-96" > + <title>cro1 radiozurnal</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow4.live.cz/cro2-96" > + <title>cro2 praha</title> + </bookmark> + <bookmark icon="sound" href="http://amp1.cesnet.cz:8000/cro3.ogg" > + <title>cro3 vltava</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/crocb48" > + <title>cro ceske budejovice</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/crohk48" > + <title>cro hradec kralove</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/crool48" > + <title>cro olomouc</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/croov48" > + <title>cro ostrava</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/croplzen64" > + <title>cro plzen</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/croregion48" > + <title>cro stredni cechy</title> + </bookmark> + </folder> + <bookmark icon="sound" href="http://amp.cesnet.cz:8000/akropolis.ogg" > + <title>radio akropolis</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/krokodyl32" > + <title>krokodyl</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/joeradioi64" > + <title>joe</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/croregina-32" > + <title>regina</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/kisshady32" > + <title>kiss hady</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/proglas32" > + <title>proglas</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow4.live.cz/country128" > + <title>country radio</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/kissproton32" > + <title>proton</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.atlas.cz/beat32" > + <title>radio beat</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/expres128" > + <title>expresradio</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/kiss64" > + <title>kiss 98 fm</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/radio164" > + <title>radio1</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/kisspublikum48" > + <title>kiss publikum</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/apollo64" > + <title>radio apollo</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/evropa2-32" > + <title>evropa 2</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/crystal64" > + <title>radio crystal</title> + </bookmark> + <bookmark icon="sound" href="mms://195.113.135.100/northmusic" > + <title>northmusic</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/sumava64" > + <title>radio sumava</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/karolina64" > + <title>radio karolina</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/hity64" > + <title>fajn radio hity</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/kisspublikum48" > + <title>kiss fm</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/kissmorava48" > + <title>kiss morava</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/cernahora128" > + <title>cerna hora</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/fmplus64" > + <title>radio fm plus</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/helax128" > + <title>helax</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/impuls128" > + <title>radio impuls</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow4.live.cz/inforadio128" > + <title>radio info</title> + </bookmark> + <bookmark icon="sound" href="mms://netshow3.live.cz/life64" > + <title>radio life fajn</title> + </bookmark> + <bookmark icon="sound" href="mms://82.208.28.37/relax64" > + <title>radio relax</title> + </bookmark> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>denmark</title> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch01m?wmcontentbitrate=300000/.wma" > + <title>P1</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch02m?wmcontentbitrate=300000/.wma" > + <title>P2</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch03m?wmcontentbitrate=300000" > + <title>P3</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch04m?wmcontentbitrate=300000/.wma" > + <title>Kanal 94</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch06m?wmcontentbitrate=300000/.wma" > + <title>Radio Fyn</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch08m?wmcontentbitrate=300000/.wma" > + <title>Bornholms Radio</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch07m?wmcontentbitrate=300000/.wma" > + <title>Regionalen</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch09m?wmcontentbitrate=300000/.wma" > + <title>Københavns Radio</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch05m?wmcontentbitrate=300000/.wma" > + <title>Radio Syd</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch03m?wmcontentbitrate=300000/.wma" > + <title>Østjyllands Radio</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch02m?wmcontentbitrate=300000/.wma" > + <title>Radio Midt & Vest</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch09m?wmcontentbitrate=300000/.wma" > + <title>DR Barometer</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch07m?wmcontentbitrate=300000/.wma" > + <title>DR Boogieradio</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e06ch02m?wmcontentbitrate=300000/.wma" > + <title>DR Erhverv</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch08m?wmcontentbitrate=300000/.wma" > + <title>DR Ghetto</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e06ch01m?wmcontentbitrate=300000/.wma" > + <title>DR Gyldne Genhør</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch05m?wmcontentbitrate=300000/.wma" > + <title>DR Jazz</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch06m?wmcontentbitrate=300000/.wma" > + <title>DR Klassisk</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch11m?wmcontentbitrate=300000/.wma" > + <title>DR Nyheder</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e02ch04m?wmcontentbitrate=300000/.wma" > + <title>DR Rock</title> + </bookmark> + <bookmark icon="sound" href="http://wmsc.dr.dk/e04ch10m?wmcontentbitrate=300000/.wma" > + <title>DR Soft</title> + </bookmark> + <bookmark icon="sound" href="http://wms.dr.dk/e02ch12m?wmcontentbitrate=300000/.wma" > + <title>DR Sport</title> + </bookmark> + </folder> + <folder folded="yes" > + <folder folded="yes" > + <title>TV</title> + <bookmark icon="video" href="http://www.itele.fr/smi/direct.smi" > + <title>I Télévision</title> + </bookmark> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveFR_nb.ram" > + <title>Bloomberg TV France</title> + </bookmark> + <bookmark icon="video" href="http://www.bbc.co.uk/newsa/n5ctrl/tvseq/n24.ram" > + <title>bbc news</title> + </bookmark> + </folder> + <title>france</title> + <bookmark icon="sound" href="mms://vip8.yacast.fr/encodereurope1" > + <title>europe1</title> + </bookmark> + <bookmark icon="sound" href="mms://vip6.yacast.fr/encodercheriefm" > + <title>cherie FM</title> + </bookmark> + <bookmark icon="sound" href="mms://viptvr.yacast.fr/tvr_vibration?site" > + <title>vibration</title> + </bookmark> + <bookmark icon="sound" href="http://www.tv-radio.com/station/rfi/rfi-20k.asx" > + <title>rfi</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.tv-radio.fr:1441/encoderfinter.ogg" > + <title>france-inter</title> + </bookmark> + <bookmark icon="sound" href="mms://viptvr2.yacast.fr/encoderfranceinfo" > + <title>france info</title> + </bookmark> + <bookmark icon="sound" href="mms://vip6.yacast.fr/encoderrmc" > + <title>rmc</title> + </bookmark> + <bookmark icon="sound" href="mms://vip6.yacast.fr/encoderrtl" > + <title>rtl</title> + </bookmark> + <bookmark icon="sound" href="mms://vip6.yacast.fr/encodernrj" > + <title>nrj</title> + </bookmark> + <bookmark icon="sound" href="mms://vip6.yacast.fr/encodernostalgie" > + <title>nostalgie</title> + </bookmark> + <bookmark icon="sound" href="mms://vip2.yacast.fr/encoderfun" > + <title>fun</title> + </bookmark> + <bookmark icon="sound" href="http://stream.servstream.com/ViewWeb/BBCRadio_music/Event/BBCRadio7.asx" > + <title>bbc 7</title> + </bookmark> + <bookmark icon="sound" href="http://www.live365.com/play/127730?membername=abfjungle" > + <title>abf</title> + </bookmark> + <bookmark icon="sound" href="mms://viptvr2.yacast.fr/tvr_europe2" > + <title>europe 2</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.tv-radio.fr:1441/encoderfip.ogg" > + <title>fip</title> + </bookmark> + <bookmark icon="sound" href="mms://viptvr.yacast.fr/tvr_franceculture" > + <title>franceculture</title> + </bookmark> + <bookmark icon="sound" href="mms://viptvr2.yacast.fr/tvr_rfm" > + <title>rfm</title> + </bookmark> + <bookmark icon="sound" href="mms://vip2.yacast.fr/encoderrtl2" > + <title>rtl2</title> + </bookmark> + <bookmark icon="sound" href="mms://vip2.yacast.fr/encoderskyrock" > + <title>skyrock</title> + </bookmark> + <bookmark icon="sound" href="mms://vip2.yacast.fr/encoderrireetchansons" > + <title>rireet chansons</title> + </bookmark> + <bookmark icon="sound" href="mms://viptvr.yacast.fr/tvr_francemusiques2" > + <title>france musique</title> + </bookmark> + <bookmark icon="sound" href="http://trevize.letsgozik.com:44444/letsgozik_56" > + <title>Let's Go Zik</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>germany</title> + <folder folded="yes" > + <title>TV</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveDE_nb.ram" > + <title>Bloomberg TV Germany</title> + </bookmark> + <bookmark icon="video" href="http://broadcast.giga.de" > + <title>GIGA TV</title> + </bookmark> + </folder> + <bookmark icon="sound" href="mms://213.200.75.252/antenne1$livestream.wma" > + <title>hit radio antenne 1</title> + </bookmark> + <bookmark icon="sound" href="mms://213.200.64.231/radiohamburg$livestream.wma" > + <title>radio hamburg</title> + </bookmark> + <bookmark icon="sound" href="mms://213.200.64.227/fettesradio$livestream.wma" > + <title>89.0 rtl</title> + </bookmark> + <bookmark icon="sound" href="mms://62.146.11.2/2884starfm_live.wmv?cid=47241&dummy=.wmv" > + <title>107.8 star fm</title> + </bookmark> + <bookmark icon="sound" href="rtsp://213.200.64.166/farm/pull2/62.89.187.100%3A2030/encoder/rockland/livestream.rm" > + <title>rockland sachsen-anhalt</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>greece</title> + <bookmark icon="sound" href="http://64.246.32.39:8906/" > + <title>Cosmoradio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>hungary</title> + <bookmark icon="sound" href="http://yp.tilos.hu:9000/tilos_high.ogg" > + <title>Tilos Radio </title> + </bookmark> + <bookmark icon="sound" href="http://195.184.2.4:8000/" > + <title>Csaba Radio</title> + </bookmark> + <bookmark icon="sound" href="http://broadcast.jazzradio.hu/jazzradio-128" > + <title>Jazz Radio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>ireland</title> + <bookmark icon="sound" href="http://69.57.152.94:8000" > + <title>Live Ireland</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>italy</title> + <folder folded="yes" icon="bookmark_folder" > + <title>TV</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveIT_nb.ram" > + <title>Bloomberg TV Italy</title> + </bookmark> + </folder> + <bookmark icon="sound" href="mms://62.101.104.172/company" > + <title>Company</title> + </bookmark> + <bookmark icon="sound" href="http://213.92.19.12:80/radiodeejay2?MSWMExt=.asf" > + <title>DeeJay</title> + </bookmark> + <bookmark icon="sound" href="mms://livemedia.kataweb.it/Radio_m2o" > + <title>M2O</title> + </bookmark> + <bookmark icon="sound" href="rtsp://live.media.rai.it/broadcast/radiouno.rm" > + <title>Radio Uno</title> + </bookmark> + <bookmark icon="sound" href="rtsp://live.media.rai.it/broadcast/radiodue.rm" > + <title>Radio Due</title> + </bookmark> + <bookmark icon="sound" href="rtsp://live.media.rai.it/broadcast/radiotre.rm" > + <title>Radio Tre</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>macedonia</title> + <bookmark icon="sound" href="http://195.26.152.92:8000/" > + <title>City Radio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>netherlands</title> + <bookmark icon="video" href="http://cgi.omroep.nl/cgi-bin/streams?/tv/nos/journaal/bb.laatste.rm" > + <title>NOS Journaal</title> + </bookmark> + <bookmark icon="sound" href="http://213.10.138.62:8000" > + <title>DBS Radio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>norway</title> + <bookmark icon="sound" href="http://radio.metalexpress.no:7128" > + <title>metal express</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>russia</title> + <bookmark icon="sound" href="http://horus.mtu.ru:9000/" > + <title>Europa Plus</title> + </bookmark> + <bookmark icon="sound" href="http://channel1.region72.ru:8000" > + <title>Red Army Radio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>san marino</title> + <bookmark icon="video" href="mms://streaming-1.intelcom.sm/Live Radio" > + <title>san marino</title> + </bookmark> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>slovakia</title> + <folder folded="yes" icon="bookmark_folder" > + <title>TV</title> + <bookmark icon="video" href="http://www.joj.sk/tvarchiv/video/playlist/playlist.wvx?video=random" > + <title>joj</title> + </bookmark> + <bookmark icon="video" href="mmsh://mslive2.markiza.sk/markiza/" > + <title>markíza</title> + </bookmark> + </folder> + <bookmark icon="sound" href="http://www.flash.viapvt.sk/Zive_vysielanie.ram" > + <title>flash</title> + </bookmark> + <bookmark icon="sound" href="http://ra.slovakradio.sk:8000/RockFM_Live_32_kb" > + <title>RockFM</title> + </bookmark> + <bookmark icon="sound" href="http://stream.radiozet.sk:8000/radiozet96kbit" > + <title>zet</title> + </bookmark> + <bookmark icon="sound" href="http://ra.slovakradio.sk:8000/SlovakRadio_Live_32_kb" > + <title>slovensko</title> + </bookmark> + <bookmark icon="sound" href="mmsh://195.98.128.202:80/twist" > + <title>twist radio</title> + </bookmark> + <bookmark icon="sound" href="http://www.rferl.org/realaudio/c13.ram" > + <title>Radio Slobodna Europa</title> + </bookmark> + <bookmark icon="sound" href="http://www.bbc.co.uk/slovak/vak.ram" > + <title>BBC World Service Slovak</title> + </bookmark> + <bookmark icon="sound" href="http://62.168.116.98:8000/dsp0" > + <title>fun radio</title> + </bookmark> + <bookmark icon="sound" href="mms://live.okey.sk/OKEY" > + <title>radio okey</title> + </bookmark> + <bookmark icon="sound" href="http://www.lumen.sk/real/live.ram" > + <title>lumen</title> + </bookmark> + <bookmark icon="sound" href="http://www.internetradio.cz/duha.asx" > + <title>duha</title> + </bookmark> + <bookmark icon="sound" href="mms://81.0.210.137/nradio" > + <title>nradio</title> + </bookmark> + <bookmark icon="sound" href="http://live.jaseus.sk:8000/rf32.ogg" > + <title>frontinus</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>slovenia</title> + <bookmark icon="sound" href="http://193.95.242.36:8000/" > + <title>Libra Radio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>spain</title> + <folder folded="yes" icon="bookmark_folder" > + <title>TV</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveES_nb.ram" > + <title>Bloomberg TV Spain</title> + </bookmark> + </folder> + <bookmark icon="sound" href="http://www.onamallorca.net:8000/ona.ogg" > + <title>Ona Mallorca</title> + </bookmark> + <bookmark icon="sound" href="http://217.125.97.68:80/" > + <title>Alpicat Radio</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>united kingdom</title> + <folder folded="yes" icon="bookmark_folder" > + <title>virgin radio</title> + <bookmark icon="sound" href="http://ogg.smgradio.com/vr32.ogg" > + <title>1215AM</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.smgradio.com/vr160.ogg" > + <title>1215AM (broadband)</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.smgradio.com/vc32.ogg" > + <title>classic rock</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.smgradio.com/vc160.ogg" > + <title>classic rock (broadband)</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.smgradio.com/gr32.ogg" > + <title>groove</title> + </bookmark> + <bookmark icon="sound" href="http://ogg.smgradio.com/gr160.ogg" > + <title>groove (broadband)</title> + </bookmark> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>TV</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveUK_nb.ram" > + <title>Bloomberg TV UK</title> + </bookmark> + </folder> + <bookmark icon="sound" href="http://live.urn1350.net:8080/urn_high.ogg" > + <title>URN</title> + </bookmark> + </folder> + </folder> + <folder folded="yes" icon="bookmark_folder" > + <title>North America</title> + <folder folded="yes" > + <title>USA</title> + <folder folded="yes" icon="bookmark_folder" > + <title>TV</title> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveBTV56.ramx" > + <title>Bloomberg TV US</title> + </bookmark> + <bookmark icon="video" href="http://www.bloomberg.com/streams/video/LiveBTV200.ramx" > + <title>Bloomberg TV US (broadband)</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>NH</title> + <bookmark icon="sound" href="http://www.WNTK.COM/audio/wntk.ram" > + <title>WNTK</title> + </bookmark> + <bookmark icon="sound" href="http://wunh.unh.edu:8000/" > + <title>WUNH</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>NY</title> + <bookmark icon="sound" href="http://205.188.234.68:8002" > + <title>Digitally Imported - EuroDance</title> + </bookmark> + <bookmark icon="sound" href="http://64.236.34.97:80/stream/1019" > + <title>Digitally Imported - Modern Jazz</title> + </bookmark> + <bookmark icon="sound" href="http://69.31.76.84:8000" > + <title>MostlyClassical.com</title> + </bookmark> + </folder> + <bookmark icon="sound" href="mms://media.apex2000.net/KQRX" > + <title>kqrx 95x</title> + </bookmark> + <bookmark icon="sound" href="rtsp://media.monroe.edu/encoder/live2.ra" > + <title>wber 90.5 fm</title> + </bookmark> + <bookmark icon="sound" href="rtsp://streamer.kozt.com/encoder/live.rm" > + <title>the coast kozt fm</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>Canada</title> + <bookmark icon="sound" href="http://caracal.rttinc.com:8002/" > + <title>CIZZ Zed 99 </title> + </bookmark> + <bookmark icon="sound" href="http://caracal.rttinc.com:8004/" > + <title>CKGY Country </title> + </bookmark> + <bookmark icon="sound" href="http://oggtrial.nm.cbc.ca:80/cbcr1-toronto.ogg" > + <title>CBC - radioONE</title> + </bookmark> + </folder> + <folder folded="yes" > + <title>Mexico</title> + <bookmark icon="sound" href="http://66.98.138.13:9520/" > + <title>XEMA B15 </title> + </bookmark> + </folder> + </folder> +</xbel> diff --git a/src/example_kjsembed.js b/src/example_kjsembed.js new file mode 100644 index 0000000..3412398 --- /dev/null +++ b/src/example_kjsembed.js @@ -0,0 +1,38 @@ +#!/usr/bin/env kjscmd + +/** + * Simple video widget added to your own KJSEmbed application that plays a movie + */ + +// Create main view +var mw = new KMainWindow(); +var box = new QVBox( mw ); +mw.setCentralWidget(box); + +var part = Factory.createROPart("application/x-kmplayer", box, "video_win"); + +/** + * KJS Bindings for KDE-3.3 also allows passing extra arguments to the part + * This allows to split of the control panel from the video widget: + +var part = Factory.createROPart("application/x-kmplayer", "'KParts/ReadOnlyPart' in ServiceTypes", box, "video_win", ["CONSOLE=foo", "CONTROLS=ImageWindow"]); +var part1 = Factory.createROPart("application/x-kmplayer", "'KParts/ReadOnlyPart' in ServiceTypes", box, "control_win", ["CONSOLE=foo", "CONTROLS=ControlPanel"]); + + * The order in which the part are created doesn't really matter. Also on which + * part openURL is called should not make a difference + */ + +/** + * There are at least two ways to communicate with kmplayer part + * 1. use the slots of the part (see below), an array of slots is returned by + * part.slots() + * 2. use kmplayer's DCOP interface + */ + +var stopbutton = new QPushButton( box, 'Stop' ); +stopbutton.text = "&Stop"; +mw.connect( stopbutton, 'clicked()', part, 'stop()' ); +part.openURL( "file:/home/koos/doc/example.avi" ); + +mw.show(); +application.exec(); diff --git a/src/example_smil.html b/src/example_smil.html new file mode 100644 index 0000000..c7a29da --- /dev/null +++ b/src/example_smil.html @@ -0,0 +1,59 @@ +<html><head><title>crash.html</title></head> +<script> +var entriecount = 0; +var currentid = -1; +function writeMenu(node, doc) { + if (!node) return; + if (node.nodeName == "video") { + var src = node.getAttribute("src"); + var title = node.getAttribute("title"); + if (!title || title == "") + title = "no title"; + doc.write("<tr><td id='" + entriecount + "'><a href=\"javascript:top.play(" + entriecount + ",'" + src + "')\">" + title + "</a></td></tr>"); + entriecount++; + } + for (var i = 0; i < node.childNodes.length; i++) + writeMenu(node.childNodes.item(i), doc); +} +function loadXML(url) { + try { + var xmldoc = document.implementation.createDocument("", "", null); + xmldoc.async = false; + xmldoc.load(url); + var doc = menuframe.document; + doc.open(); + doc.write("<html><style>\nbody {color:#a0a0a0;background-color:#323232;}\ntd {font-size:9pt;}\na {color:#fffff0;}\n</style><body bgcolor='#323232'><table>"); + entriecount = 0; + writeMenu(xmldoc.firstChild, doc); + doc.write("</table></body></html>"); + doc.close(); + doc = playerframe.document; + doc.open(); + doc.write("<html><body bgcolor='#161616'></body></html>"); + doc.close(); + } catch(ex) { + alert ("Error: " + ex); + } +} +function play(id, url) { + if (currentid > -1) { + var td = menuframe.document.getElementById(currentid); + td.style.backgroundColor = '#323232'; + } + var td = menuframe.document.getElementById(id); + td.style.backgroundColor = '#646464'; + currentid = id; + var doc = playerframe.document; + doc.open(); + doc.write("<html><body bgcolor='#161616'><embed type='video/x-ms-wmv' src='" + url + "' width='100%' height='100%'><script>\nfunction onFinished(){top.finished(" + id + ");}\n<\/script></embed></body></html>"); + doc.close(); +} +function finished(id) { + var td = menuframe.document.getElementById(id); + td.style.backgroundColor = '#323232'; +} +</script> +<frameset cols="200,*" onLoad="loadXML('file:/your-smil.xml')"> + <frame name="menuframe" src="about:blank"> + <frame name="playerframe" src="about:blank"> +</html> diff --git a/src/gstplayer.cpp b/src/gstplayer.cpp new file mode 100644 index 0000000..092a8b2 --- /dev/null +++ b/src/gstplayer.cpp @@ -0,0 +1,1027 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <config.h> +#include <dcopclient.h> +#include <qcstring.h> +#include <qtimer.h> +#include <qfile.h> +#include <qurl.h> +#include <qthread.h> +#include <qmutex.h> +#include <qdom.h> +#include "kmplayer_backend.h" +#include "kmplayer_callback_stub.h" +#include "kmplayer_callback.h" +#include "gstplayer.h" +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <gst/gst.h> +#include <gst/interfaces/xoverlay.h> +#include <gst/interfaces/colorbalance.h> + +static char configfile[2048]; + +static Display *display; +static KGStreamerPlayer *gstapp; +static KMPlayer::Callback_stub * callback; +static Window wid; +static QMutex mutex (true); +static bool window_created = true; +static bool wants_config; +static bool verbose; +static bool notified_playing; +static int running; +static int movie_width; +static int movie_height; +static int movie_length; +static int repeat_count; +static int screen; +static const int event_finished = QEvent::User; +static const int event_playing = QEvent::User + 1; +static const int event_size = QEvent::User + 2; +static const int event_eos = QEvent::User + 3; +static const int event_progress = QEvent::User + 4; +static const int event_error = QEvent::User + 5; +static const int event_video = QEvent::User + 6; +static QString mrl; +static QString sub_mrl; +static const char *ao_driver; +static const char *vo_driver; +static const char *playbin_name = "player"; +static const char *dvd_device; +static const char *vcd_device; +static GstElement *gst_elm_play; +static GstBus *gst_bus; +static unsigned int /*GstMessageType*/ ignore_messages_mask; +static GstXOverlay *xoverlay; +static GstColorBalance *color_balance; +static gulong gst_bus_sync; +static gulong gst_bus_async; +static QString elmentry ("entry"); +static QString elmitem ("item"); +static QString attname ("NAME"); +static QString atttype ("TYPE"); +static QString attdefault ("DEFAULT"); +static QString attvalue ("VALUE"); +static QString attstart ("START"); +static QString attend ("END"); +static QString valrange ("range"); +static QString valnum ("num"); +static QString valbool ("bool"); +static QString valenum ("enum"); +static QString valstring ("string"); + +extern "C" { + // nothing yet +} // extern "C" + + +static bool gstPollForStateChange (GstElement *, GstState, gint64=GST_SECOND/2); + +static void +cb_error (GstElement * play, + GstElement * /*src*/, + GError *err, + const char *debug, + gpointer /*data*/) +{ + fprintf (stderr, "cb_error: %s %s\n", err->message, debug); + if (GST_STATE (play) == GST_STATE_PLAYING) + gst_element_set_state (play, GST_STATE_READY); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type)event_finished)); +} + +// NULL -> READY -> PAUSED -> PLAYING + +static void +gstCapsSet (GstPad *pad, + GParamSpec * /*pspec*/, + gpointer /*data*/) +{ + GstCaps *caps = gst_pad_get_negotiated_caps (pad); + if (!caps) + return; + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_video)); + const GstStructure * s = gst_caps_get_structure (caps, 0); + if (s) { + const GValue *par; + + gst_structure_get_int (s, "width", &movie_width); + gst_structure_get_int (s, "height", &movie_height); + if ((par = gst_structure_get_value (s, "pixel-aspect-ratio"))) { + int num = gst_value_get_fraction_numerator (par), + den = gst_value_get_fraction_denominator (par); + + if (num > den) + movie_width = (int) ((float) num * movie_width / den); + else + movie_height = (int) ((float) den * movie_height / num); + } + QApplication::postEvent (gstapp, new GstSizeEvent (movie_length, movie_width, movie_height)); + } + gst_caps_unref (caps); +} + +static void gstStreamInfo (GObject *, GParamSpec *, gpointer /*data*/) { + GstPad *videopad = 0L; + GList *streaminfo = 0L; + + fprintf (stderr, "gstStreamInfo\n"); + g_object_get (gst_elm_play, "stream-info", &streaminfo, NULL); + streaminfo = g_list_copy (streaminfo); + g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL); + for ( ; streaminfo != NULL; streaminfo = streaminfo->next) { + GObject *info = G_OBJECT (streaminfo->data); + gint type; + GParamSpec *pspec; + GEnumValue *val; + + if (!info) + continue; + g_object_get (info, "type", &type, NULL); + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(info), "type"); + val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type); + + if (!g_strcasecmp (val->value_nick, "video")) + if (!videopad) { + g_object_get (info, "object", &videopad, NULL); + gstCapsSet (GST_PAD (videopad), 0L, 0L); + g_signal_connect (videopad, "notify::caps", G_CALLBACK (gstCapsSet), 0L); + } + } + + GstMessage * msg = gst_message_new_application (GST_OBJECT (gst_elm_play), + gst_structure_new ("notify-streaminfo", NULL)); + gst_element_post_message (gst_elm_play, msg); + g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL); + g_list_free (streaminfo); +} + +static void gstSource (GObject *, GParamSpec *, gpointer /*data*/) { + GObject *source = 0L; + fprintf (stderr, "gstSource\n"); + g_object_get (gst_elm_play, "source", &source, NULL); + if (!source) + return; + GObjectClass *klass = G_OBJECT_GET_CLASS (source); + if (mrl.startsWith ("dvd://") && dvd_device) { + if (g_object_class_find_property (klass, "device")) + g_object_set (source, "device", dvd_device, NULL); + } else if (mrl.startsWith ("vcd://") && vcd_device) { + if (g_object_class_find_property (klass, "device")) + g_object_set (source, "device", vcd_device, NULL); + } + g_object_unref (source); +} + +static void gstGetDuration () { + GstFormat fmt = GST_FORMAT_TIME; + gint64 len = -1; // usec + if (gst_element_query_duration (gst_elm_play, &fmt, &len)) + if (movie_length != len / (GST_MSECOND * 100)) { + movie_length = len / (GST_MSECOND * 100); + fprintf (stderr, "new length %d\n", movie_length); + QApplication::postEvent (gstapp, new GstSizeEvent (movie_length, movie_width, movie_height)); + } +} + +static void gstTag (const GstTagList *, const gchar *tag, gpointer) { + fprintf (stderr, "Tag: %s\n", tag); +} + +//static bool gstStructure (GQuark field_id, const GValue *value, gpointer user_data); + +static void gstBusMessage (GstBus *, GstMessage * message, gpointer) { + GstMessageType msg_type = GST_MESSAGE_TYPE (message); + /* somebody else is handling the message, probably in gstPolForStateChange*/ + if (ignore_messages_mask & msg_type) + return; + switch (msg_type) { + case GST_MESSAGE_ERROR: + fprintf (stderr, "error msg\n"); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_error)); + if (gst_elm_play) { + gst_element_set_state (gst_elm_play, GST_STATE_NULL); + //gstPollForStateChange (gst_elm_play, GST_STATE_NULL); + } + break; + case GST_MESSAGE_WARNING: + fprintf (stderr, "warning msg\n"); + break; + case GST_MESSAGE_TAG: { + GstTagList *tag_list; + //fprintf (stderr, "tag msg\n"); + gst_message_parse_tag (message, &tag_list); + gst_tag_list_foreach (tag_list, gstTag, 0L); + gst_tag_list_free (tag_list); + break; + } + case GST_MESSAGE_EOS: + fprintf (stderr, "eos msg\n"); + gst_element_set_state (gst_elm_play, GST_STATE_READY); + break; + case GST_MESSAGE_BUFFERING: { + gint percent = 0; + gst_structure_get_int (message->structure, "buffer-percent", &percent); + QApplication::postEvent (gstapp, new GstProgressEvent (percent)); + //fprintf (stderr, "Buffering message (%u%%)\n", percent); + break; + } + case GST_MESSAGE_APPLICATION: { + const char * msg = gst_structure_get_name (message->structure); + fprintf (stderr, "app msg %s\n", msg ? msg : "<unknown>"); + //gst_structure_foreach (message->structure, gstStructure, 0L); + break; + } + case GST_MESSAGE_STATE_CHANGED: { + GstState old_state, new_state; + //gchar *src_name = gst_object_get_name (message->src); + gst_message_parse_state_changed(message, &old_state, &new_state,0L); + //fprintf (stderr, "%s changed state from %s to %s\n", src_name, gst_element_state_get_name (old_state), gst_element_state_get_name (new_state)); + if (GST_IS_ELEMENT (message->src) && + GST_ELEMENT (message->src) == gst_elm_play) { + if (old_state == GST_STATE_PAUSED && + new_state >= GST_STATE_PLAYING) { + gstGetDuration (); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_playing)); + } else if (old_state >= GST_STATE_PAUSED && + new_state <= GST_STATE_READY) { + if (repeat_count-- > 0 && + (gst_element_set_state(gst_elm_play, GST_STATE_PAUSED), + gstPollForStateChange(gst_elm_play, GST_STATE_PAUSED))) + gst_element_set_state(gst_elm_play, GST_STATE_PLAYING); + else + QApplication::postEvent (gstapp, + new QEvent ((QEvent::Type) event_finished)); + } + } + //g_free (src_name); + break; + } + case GST_MESSAGE_DURATION: + gstGetDuration (); + break; + case GST_MESSAGE_CLOCK_PROVIDE: + case GST_MESSAGE_CLOCK_LOST: + case GST_MESSAGE_NEW_CLOCK: + case GST_MESSAGE_STATE_DIRTY: + break; + default: + fprintf (stderr, "Unhandled msg %s (0x%x)\n", + gst_message_type_get_name (msg_type), msg_type); + break; + } +} + +static void gstMessageElement (GstBus *, GstMessage *msg, gpointer /*data*/) { + if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) { + fprintf (stderr, "prepare-xwindow-id\n"); + if (xoverlay) + gst_x_overlay_set_xwindow_id (xoverlay, wid); + } +} + +static bool gstPollForStateChange (GstElement *element, GstState state, gint64 timeout) { + /*GstMessageType*/ unsigned int events, saved_events; + GstBus *bus = gst_element_get_bus (element); + GError **error = 0L; + + events = GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS; + saved_events = ignore_messages_mask; + + if (element && element == gst_elm_play) { + /* we do want the main handler to process state changed messages for + * playbin as well, otherwise it won't hook up the timeout etc. */ + ignore_messages_mask |= (events ^ GST_MESSAGE_STATE_CHANGED); + } else { + ignore_messages_mask |= events; + } + + while (true) { + GstMessage *message; + GstElement *src; + + message = gst_bus_poll (bus, (GstMessageType) events, timeout); + if (!message) + goto timed_out; + + src = (GstElement*)GST_MESSAGE_SRC (message); + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STATE_CHANGED: { + GstState olds, news, pending; + if (src == element) { + gst_message_parse_state_changed (message, &olds, &news, &pending); + if (news == state) { + gst_message_unref (message); + goto success; + } + } + break; + } + case GST_MESSAGE_ERROR: { + gchar *debug = NULL; + GError *gsterror = NULL; + gst_message_parse_error (message, &gsterror, &debug); + fprintf (stderr, "Error: %s (%s)\n", gsterror->message, debug); + gst_message_unref (message); + g_error_free (gsterror); + g_free (debug); + goto error; + } + case GST_MESSAGE_EOS: { + gst_message_unref (message); + goto error; + } + default: + g_assert_not_reached (); + break; + } + gst_message_unref (message); + } + g_assert_not_reached (); + +success: + /* state change succeeded */ + fprintf (stderr, "state change to %s succeeded\n", gst_element_state_get_name (state)); + ignore_messages_mask = saved_events; + return true; + +timed_out: + /* it's taking a long time to open -- just tell totem it was ok, this allows + * the user to stop the loading process with the normal stop button */ + fprintf (stderr, "state change to %s timed out, returning success and handling errors asynchroneously\n", gst_element_state_get_name (state)); + ignore_messages_mask = saved_events; + return true; + +error: + fprintf (stderr, "error while waiting for state change to %s: %s\n", + gst_element_state_get_name (state), + (error && *error) ? (*error)->message : "unknown"); + /* already set *error */ + ignore_messages_mask = saved_events; + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_error)); + return false; +} + +//----------------------------------------------------------------------------- + +GstSizeEvent::GstSizeEvent (int l, int w, int h) + : QEvent ((QEvent::Type) event_size), + length (l), width (w), height (h) +{} + +GstProgressEvent::GstProgressEvent (const int p) + : QEvent ((QEvent::Type) event_progress), progress (p) +{} + +//----------------------------------------------------------------------------- + +using namespace KMPlayer; + +Backend::Backend () + : DCOPObject (QCString ("Backend")) { +} + +Backend::~Backend () {} + +void Backend::setURL (QString url) { + mrl = url; +} + +void Backend::setSubTitleURL (QString url) { + sub_mrl = url; +} + +void Backend::play (int repeat) { + gstapp->play (repeat); +} + +void Backend::stop () { + QTimer::singleShot (0, gstapp, SLOT (stop ())); +} + +void Backend::pause () { + gstapp->pause (); +} + +void Backend::seek (int v, bool /*absolute*/) { + gstapp->seek (v); +} + +void Backend::hue (int h, bool) { + gstapp->hue (h); +} + +void Backend::saturation (int s, bool) { + gstapp->saturation (s); +} + +void Backend::contrast (int c, bool) { + gstapp->contrast (c); +} + +void Backend::brightness (int b, bool) { + gstapp->brightness (b); +} + +void Backend::volume (int v, bool) { + gstapp->volume (v); +} + +void Backend::frequency (int) { +} + +void Backend::setAudioLang (int, QString) { +} + +void Backend::setSubtitle (int, QString) { +} + +void Backend::quit () { + delete callback; + callback = 0L; + if (running) + stop (); + else + QTimer::singleShot (0, qApp, SLOT (quit ())); +} + +bool updateConfigEntry (const QString & name, const QString & value) { + fprintf (stderr, "%s=%s\n", name.ascii (), (const char *) value.local8Bit ()); + return true; +} + +void Backend::setConfig (QByteArray /*data*/) { + /*QString err; + int line, column; + QDomDocument dom; + if (dom.setContent (data, false, &err, &line, &column)) { + if (dom.childNodes().length() == 1) { + for (QDomNode node = dom.firstChild().firstChild(); + !node.isNull (); + node = node.nextSibling ()) { + QDomNamedNodeMap attr = node.attributes (); + updateConfigEntry (attr.namedItem (attname).nodeValue (), + attr.namedItem (attvalue).nodeValue ()); + } + } else + err = QString ("invalid data"); + } + if (callback) + callback->errorMessage (0, err);*/ +} + +bool Backend::isPlaying () { + mutex.lock (); + bool b = gst_elm_play && (GST_STATE (gst_elm_play) == GST_STATE_PLAYING); + mutex.unlock (); + return b; +} + +KGStreamerPlayer::KGStreamerPlayer (int _argc, char ** _argv) + : QApplication (_argc, _argv, false) { +} + +void KGStreamerPlayer::init () { + int xpos = 0; + int ypos = 0; + int width = 320; + int height = 200; + + XLockDisplay(display); + if (window_created) + wid = XCreateSimpleWindow(display, XDefaultRootWindow(display), + xpos, ypos, width, height, 1, 0, 0); + fprintf (stderr, "init wid %u created:%d\n", wid, window_created); + XSelectInput (display, wid, + (PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask)); // | SubstructureNotifyMask)); + + if (window_created) { + //fprintf (stderr, "map %lu\n", wid); + XMapRaised(display, wid); + XSync(display, False); + } + XUnlockDisplay(display); +} + +KGStreamerPlayer::~KGStreamerPlayer () { + if (window_created) { + XLockDisplay (display); + fprintf (stderr, "unmap %lu\n", wid); + XUnmapWindow (display, wid); + XDestroyWindow(display, wid); + XSync (display, False); + XUnlockDisplay (display); + } + gstapp = 0L; +} + +void getConfigEntries (QByteArray & buf) { + QDomDocument doc; + QDomElement root = doc.createElement (QString ("document")); + doc.appendChild (root); + QCString exp = doc.toCString (); + buf = exp; + buf.resize (exp.length ()); // strip terminating \0 +} + +void KGStreamerPlayer::play (int repeat) { + GstElement *element; + GstElement *videosink = 0L; + GstElement *audiosink = 0L; + bool success; + fprintf (stderr, "play %s\n", mrl.isEmpty() ? "<empty>" : mrl.ascii ()); + if (gst_elm_play) { + if (GST_STATE (gst_elm_play) == GST_STATE_PAUSED) { + gst_element_set_state (gst_elm_play, GST_STATE_PLAYING); + gstPollForStateChange (gst_elm_play, GST_STATE_PLAYING); + } + return; + } + notified_playing = false; + if (mrl.isEmpty ()) + return; + gchar *uri, *sub_uri = 0L; + movie_length = movie_width = movie_height = 0; + mutex.lock (); + gst_elm_play = gst_element_factory_make ("playbin", playbin_name); + if (!gst_elm_play) { + fprintf (stderr, "couldn't create playbin\n"); + goto fail; + } + ignore_messages_mask = 0; + gst_bus = gst_element_get_bus (gst_elm_play); + + gst_bus_add_signal_watch (gst_bus); + + gst_bus_async = g_signal_connect (gst_bus, "message", + G_CALLBACK (gstBusMessage), 0L); + if (ao_driver && !strncmp (ao_driver, "alsa", 4)) + audiosink = gst_element_factory_make ("alsasink", "audiosink"); + else if (ao_driver && !strncmp (ao_driver, "arts", 4)) + audiosink = gst_element_factory_make ("artsdsink", "audiosink"); + else if (ao_driver && !strncmp (ao_driver, "esd", 3)) + audiosink = gst_element_factory_make ("esdsink", "audiosink"); + else + audiosink = gst_element_factory_make ("osssink", "audiosink"); + if (!audiosink) + goto fail; + if (vo_driver && !strncmp (vo_driver, "xv", 2)) + videosink = gst_element_factory_make ("xvimagesink", "videosink"); + else + videosink = gst_element_factory_make ("ximagesink", "videosink"); + if (!videosink) + goto fail; + if (GST_IS_BIN (videosink)) + element = gst_bin_get_by_interface (GST_BIN (videosink), + GST_TYPE_X_OVERLAY); + else + element = videosink; + if (GST_IS_X_OVERLAY (element)) { + xoverlay = GST_X_OVERLAY (element); + gst_x_overlay_set_xwindow_id (xoverlay, wid); + } + gst_element_set_bus (videosink, gst_bus); + gst_element_set_state (videosink, GST_STATE_READY); + success = gstPollForStateChange (videosink, GST_STATE_READY); + //if (!success) { + /* Drop this video sink */ + // gst_element_set_state (videosink, GST_STATE_NULL); + // gst_object_unref (videosink); + if (audiosink) { + gst_element_set_bus (audiosink, gst_bus); + gst_element_set_state (audiosink, GST_STATE_READY); + success = gstPollForStateChange (audiosink, GST_STATE_READY); + } + g_object_set (G_OBJECT (gst_elm_play), + "video-sink", videosink, + "audio-sink", audiosink, + NULL); + gst_bus_set_sync_handler (gst_bus, gst_bus_sync_signal_handler, 0L); + gst_bus_sync = g_signal_connect (gst_bus, "sync-message::element", + G_CALLBACK (gstMessageElement), 0L); + g_signal_connect (gst_elm_play, "notify::source", + G_CALLBACK (gstSource), 0L); + g_signal_connect (gst_elm_play, "notify::stream-info", + G_CALLBACK (gstStreamInfo), 0L); + if (GST_IS_COLOR_BALANCE (videosink)) + color_balance = GST_COLOR_BALANCE (videosink); + + if (GST_STATE (gst_elm_play) > GST_STATE_READY) + gst_element_set_state (gst_elm_play, GST_STATE_READY); + + if (mrl.startsWith (QChar ('/'))) + mrl = QString ("file://") + mrl; + uri = g_strdup (mrl.local8Bit ()); + g_object_set (gst_elm_play, "uri", uri, NULL); + if (!sub_mrl.isEmpty ()) { + if (sub_mrl.startsWith (QChar ('/'))) + sub_mrl = QString ("file://") + sub_mrl; + sub_uri = g_strdup (sub_mrl.local8Bit ()); + g_object_set (gst_elm_play, "suburi", sub_uri, NULL); + g_free (sub_uri); + } + repeat_count = repeat; + mutex.unlock (); + gst_element_set_state (gst_elm_play, GST_STATE_PAUSED); + if (gstPollForStateChange (gst_elm_play, GST_STATE_PAUSED)) { + gst_element_set_state (gst_elm_play, GST_STATE_PLAYING); + gstPollForStateChange (gst_elm_play, GST_STATE_PLAYING); + } + g_free (uri); + QTimer::singleShot (500, this, SLOT (updatePosition ())); + return; +fail: + if (videosink) { + gst_element_set_state (videosink, GST_STATE_NULL); + gst_object_unref (videosink); + } + if (audiosink) { + gst_element_set_state (audiosink, GST_STATE_NULL); + gst_object_unref (audiosink); + } + mutex.unlock (); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type)event_finished)); +} + +void KGStreamerPlayer::pause () { + mutex.lock (); + if (gst_elm_play) { + GstState state = GST_STATE (gst_elm_play) == GST_STATE_PLAYING ? + GST_STATE_PAUSED : GST_STATE_PLAYING; + gst_element_set_state (gst_elm_play, state); + gstPollForStateChange (gst_elm_play, state); + } + mutex.unlock (); +} + +void KGStreamerPlayer::stop () { + fprintf (stderr, "stop %s\n", mrl.isEmpty () ? "<empty>" : mrl.ascii ()); + mutex.lock (); + repeat_count = 0; + if (gst_elm_play) { + GstState current_state; + gst_element_get_state (gst_elm_play, ¤t_state, NULL, 0); + if (current_state > GST_STATE_READY) { + gst_element_set_state (gst_elm_play, GST_STATE_READY); + mutex.unlock (); + gstPollForStateChange (gst_elm_play, GST_STATE_READY, -1); + mutex.lock (); + } + gst_element_set_state (gst_elm_play, GST_STATE_NULL); + gst_element_get_state (gst_elm_play, NULL, NULL, -1); + } + mutex.unlock (); + if (!gst_elm_play || (gst_elm_play && !notified_playing)) + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_finished)); +} + +void KGStreamerPlayer::finished () { + QTimer::singleShot (10, this, SLOT (stop ())); +} + +static void adjustColorSetting (const char * channel, int val) { + //fprintf (stderr, "adjustColorSetting %s\n", channel); + mutex.lock (); + if (color_balance) { + for (const GList *item =gst_color_balance_list_channels (color_balance); + item != NULL; item = item->next) { + GstColorBalanceChannel *chan = (GstColorBalanceChannel*) item->data; + + if (!strstr (chan->label, channel)) + gst_color_balance_set_value (color_balance, chan, + ((val + 100) * (chan->max_value - chan->min_value)/200 + chan->min_value)); + } + } + mutex.unlock (); +} + +void KGStreamerPlayer::saturation (int s) { + adjustColorSetting ("SATURATION", s); +} + +void KGStreamerPlayer::hue (int h) { + adjustColorSetting ("HUE", h); +} + +void KGStreamerPlayer::contrast (int c) { + adjustColorSetting ("CONTRAST", c); +} + +void KGStreamerPlayer::brightness (int b) { + adjustColorSetting ("BRIGHTNESS", b); +} + +void KGStreamerPlayer::seek (int val /*offset_in_deciseconds*/) { + //fprintf (stderr, "seek %d\n", val); + mutex.lock (); + if (gst_elm_play) + gst_element_seek (gst_elm_play, 1.0, GST_FORMAT_TIME, + (GstSeekFlags) (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), + GST_SEEK_TYPE_SET, val * GST_MSECOND * 100, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + mutex.unlock (); +} + +void KGStreamerPlayer::volume (int val) { + //fprintf (stderr, "position %d\n", val); + if (gst_elm_play) + g_object_set (G_OBJECT (gst_elm_play), "volume", 1.0*val/100, 0L); +} + +void KGStreamerPlayer::updatePosition () { + if (gst_elm_play) { + do { + GstMessage * msg = gst_bus_poll (gst_bus, (GstMessageType) (GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_DURATION), GST_MSECOND * 10); + if (!msg) + break; + gst_message_unref (msg); + } while (gst_bus); + + mutex.lock (); + if (gst_elm_play && callback) { + GstFormat fmt = GST_FORMAT_TIME; + gint64 val = 0; // usec + if (gst_element_query_position (gst_elm_play, &fmt, &val)) + callback->moviePosition (int (val / (GST_MSECOND * 100))); + } + mutex.unlock (); + QTimer::singleShot (500, this, SLOT (updatePosition ())); + } +} + +bool KGStreamerPlayer::event (QEvent * e) { + switch (e->type()) { + case event_finished: { + fprintf (stderr, "event_finished\n"); + mutex.lock (); + if (gst_elm_play) { + gst_bus_set_flushing (gst_bus, true); + if (gst_bus_sync) + g_signal_handler_disconnect (gst_bus, gst_bus_sync); + if (gst_bus_async) + g_signal_handler_disconnect (gst_bus, gst_bus_async); + gst_object_unref (gst_bus); + gst_object_unref (GST_OBJECT (gst_elm_play)); + gst_bus = 0L; + gst_elm_play = 0L; + color_balance = 0L; + gst_bus_sync = gst_bus_async = 0; + xoverlay = 0L; + } + mutex.unlock (); + if (callback) + callback->finished (); + else + QTimer::singleShot (0, this, SLOT (quit ())); + break; + } + //callback->movieParams (se->length/100, se->width, se->height, se->height ? 1.0*se->width/se->height : 1.0); + case event_size: { + GstSizeEvent * se = static_cast <GstSizeEvent *> (e); + fprintf (stderr, "movie parms: %d %d %d\n", se->length, se->width, se->height); + if (callback) { + if (se->length < 0) se->length = 0; + callback->movieParams (se->length, se->width, se->height, se->height ? 1.0*se->width/se->height : 1.0, QStringList (), QStringList ()); + } + if (window_created && movie_width > 0 && movie_height > 0) { + XLockDisplay (display); + XResizeWindow (display, wid, movie_width, movie_height); + XFlush (display); + XUnlockDisplay (display); + } + // fall through + } + case event_playing: + notified_playing = true; + if (callback) + callback->playing (); + break; + case event_progress: + if (callback) + callback->loadingProgress + (static_cast <GstProgressEvent *> (e)->progress); + break; + case event_eos: + case event_error: + stop (); + break; + case event_video: + if (callback) + callback->statusMessage ((int) KMPlayer::Callback::stat_hasvideo, QString ()); + break; + default: + return false; + } + return true; +} + +void KGStreamerPlayer::saveState (QSessionManager & sm) { + if (callback) + sm.setRestartHint (QSessionManager::RestartNever); +} + +class XEventThread : public QThread { +protected: + void run () { + Time prev_click_time = 0; + int prev_click_x = 0; + int prev_click_y = 0; + while (true) { + XEvent xevent; + XNextEvent(display, &xevent); + switch(xevent.type) { + case ClientMessage: + if (xevent.xclient.format == 8 && + !strncmp(xevent.xclient.data.b, "quit_now", 8)) { + fprintf(stderr, "request quit\n"); + return; + } + break; + case KeyPress: { + XKeyEvent kevent; + KeySym ksym; + char kbuf[256]; + int len; + kevent = xevent.xkey; + XLockDisplay(display); + len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); + XUnlockDisplay(display); + fprintf(stderr, "keypressed 0x%x 0x%x\n", kevent.keycode, ksym); + switch (ksym) { + case XK_q: + case XK_Q: + gstapp->lock (); + gstapp->stop (); + gstapp->unlock (); + break; + } + break; + } + case Expose: + if (!xevent.xexpose.count && xevent.xexpose.window == wid) { + mutex.lock (); + if (gst_elm_play) { + GstElement *videosink; + g_object_get (gst_elm_play, "video-sink", &videosink, NULL); + if (videosink && GST_IS_X_OVERLAY (videosink)) { + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (videosink), wid); + gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + gst_object_unref (videosink); + } + } + mutex.unlock (); + } + break; + + case ConfigureNotify: + mutex.lock (); + if (xoverlay && GST_IS_X_OVERLAY (xoverlay)) + gst_x_overlay_expose (xoverlay); + mutex.unlock (); + break; + case ButtonPress: { + XButtonEvent *bev = (XButtonEvent *) &xevent; + int dx = prev_click_x - bev->x; + int dy = prev_click_y - bev->y; + if (bev->time - prev_click_time < 400 && + (dx * dx + dy * dy) < 25) { + gstapp->lock (); + if (callback) + callback->toggleFullScreen (); + gstapp->unlock (); + } + prev_click_time = bev->time; + prev_click_x = bev->x; + prev_click_y = bev->y; + break; + } + default: + ; //if (xevent.type < LASTEvent) + // fprintf (stderr, "event %d\n", xevent.type); + } + } + } +}; + +int main(int argc, char **argv) { + if (!XInitThreads ()) { + fprintf (stderr, "XInitThreads () failed\n"); + return 1; + } + display = XOpenDisplay(NULL); + screen = XDefaultScreen(display); + + gst_init (NULL, NULL); + + gstapp = new KGStreamerPlayer (argc, argv); + + for(int i = 1; i < argc; i++) { + if (!strcmp (argv [i], "-ao")) { + ao_driver = argv [++i]; + } else if (!strcmp (argv [i], "-vo")) { + vo_driver = argv [++i]; + } else if (!strcmp (argv [i], "-dvd-device") && ++i < argc) { + dvd_device = argv [i]; + } else if (!strcmp (argv [i], "-vcd-device") && ++i < argc) { + vcd_device = argv [i]; + } else if (!strcmp (argv [i], "-wid") || !strcmp (argv [i], "-window-id")) { + wid = atol (argv [++i]); + window_created = false; + } else if (!strcmp (argv [i], "-root")) { + wid = XDefaultRootWindow (display); + window_created = false; + } else if (!strcmp (argv [i], "-window")) { + ; + } else if (!strcmp (argv [i], "-v")) { + verbose = true; + } else if (!strcmp (argv [i], "-c")) { + wants_config = true; + } else if (!strcmp (argv [i], "-f") && i < argc - 1) { + strncpy (configfile, argv [++i], sizeof (configfile)); + configfile[sizeof (configfile) - 1] = 0; + } else if (!strcmp (argv [i], "-loop") && i < argc - 1) { + repeat_count = atol (argv [++i]); + } else if (!strcmp (argv [i], "-cb")) { + QString str = argv [++i]; + int pos = str.find ('/'); + if (pos > -1) { + fprintf (stderr, "callback is %s %s\n", str.left (pos).ascii (), str.mid (pos + 1).ascii ()); + callback = new KMPlayer::Callback_stub + (str.left (pos).ascii (), str.mid (pos + 1).ascii ()); + } + } else if (!strncmp (argv [i], "-", 1)) { + fprintf (stderr, "usage: %s [-vo (xv|xshm)] [-ao <audio driver>] [-f <config file>] [-dvd-device <device>] [-vcd-device <device>] [-v] [(-wid|-window-id) <window>] [(-root|-window)] [-cb <DCOP callback name> [-c]] [<url>]\n", argv[0]); + delete gstapp; + return 1; + } else { + mrl = QString::fromLocal8Bit (argv[i]); + } + } + + DCOPClient dcopclient; + dcopclient.registerAs ("kgstreamerplayer"); + Backend * backend = new Backend; + + XEventThread * eventThread = new XEventThread; + eventThread->start (); + + gstapp->init (); + + if (callback) { + QByteArray buf; + if (wants_config) + getConfigEntries (buf); + callback->started (dcopclient.appId (), buf); + } else + QTimer::singleShot (10, gstapp, SLOT (play (int))); + + gstapp->exec (); + + XLockDisplay(display); + XClientMessageEvent ev = { + ClientMessage, 0, true, display, wid, + XInternAtom (display, "XVIDEO", false), 8, {b: "quit_now"} + }; + XSendEvent (display, wid, false, StructureNotifyMask, (XEvent *) & ev); + XFlush (display); + XUnlockDisplay(display); + eventThread->wait (500); + delete eventThread; + + gstapp->stop (); + delete backend; + delete gstapp; + + fprintf (stderr, "closing display\n"); + XCloseDisplay (display); + fprintf (stderr, "done\n"); + fflush (stderr); + return 0; +} + +#include "gstplayer.moc" diff --git a/src/gstplayer.h b/src/gstplayer.h new file mode 100644 index 0000000..5eec508 --- /dev/null +++ b/src/gstplayer.h @@ -0,0 +1,64 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _K_GST_PLAYER_H_ +#define _K_GST_PLAYER_H_ + +#include <qapplication.h> +#include <qstring.h> +#include <qsessionmanager.h> + +struct GstSizeEvent : public QEvent { + GstSizeEvent (int l, int w, int h); + int length; + int width; + int height; +}; + +struct GstProgressEvent : public QEvent { + GstProgressEvent (int p); + int progress; +}; + +class KGStreamerPlayer : public QApplication { + Q_OBJECT +public: + KGStreamerPlayer (int argc, char ** argv); + ~KGStreamerPlayer (); + + void init (); + void finished (); + void saturation (int val); + void hue (int val); + void contrast (int val); + void brightness (int val); + void volume (int val); + void seek (int val); + bool event (QEvent * e); +public slots: + void play (int repeat_count); + void stop (); + void pause (); + void updatePosition (); + //void postFinished (); +protected: + void saveState (QSessionManager & sm); +}; + +#endif //_K_GST_PLAYER_H_ diff --git a/src/kmplayer.desktop b/src/kmplayer.desktop new file mode 100644 index 0000000..4969c07 --- /dev/null +++ b/src/kmplayer.desktop @@ -0,0 +1,100 @@ +# KDE Config File +[Desktop Entry] +Encoding=UTF-8 +Type=Application +Exec=kmplayer -caption "%c" %i %m %U +Icon=kmplayer.png +DocPath=kmplayer/index.html +Comment=KDE interface for MPlayer +Comment[af]=KDE koppelvlak na MPlayer +Comment[ar]=واجهة KDE لِــ MPlayer +Comment[be]=KDE інтэрфейс да MPlayer +Comment[bg]=KDE интерфейс за MPlayer +Comment[br]=Etrefas MPlayer evit KDE +Comment[bs]=KDE interfejs za MPlayer +Comment[ca]=Interfície KDE per a MPlayer +Comment[cs]=KDE rozhraní pro MPlayer +Comment[csb]=Interfejs KDE dlô MPlayer +Comment[da]=KDE-grænseflade for MPlayer +Comment[de]=KDE-Oberfläche für MPlayer +Comment[el]=Περιβάλλον χρήσης του MPlayer για το KDE +Comment[es]=Interfaz KDE para MPlayer +Comment[et]=KDE MPlayeri liides +Comment[fi]=KDE-käyttöliittymä MPlayerille +Comment[fr]=Une interface de MPlayer pour KDE +Comment[gl]=Interface de KDE para MPlayer +Comment[he]=ממשק KDE של MPlayer +Comment[hi]=एमप्लेयर हेतु केडीई इंटरफेस +Comment[hu]=KDE-alapú felület az MPlayerhez +Comment[it]=Interfaccia KDE per MPlayer +Comment[ja]=MPlayer の KDE インターフェース +Comment[nb]=KDE-grensesnitt for MPlayer +Comment[nl]=KDE-interface voor MPlayer +Comment[pa]=MPlayer ਲਈ KDE ਇੰਟਰਫੇਸ +Comment[pt]=Interface KDE para o MPlayer +Comment[pt_BR]=Interface do KDE para o MPlayer +Comment[ru]=Интерфейс KDE для MPlayer +Comment[sk]=KDE rozhranie pre MPlayer +Comment[sr]=KDE-ов интерфејс за MPlayer +Comment[sr@Latn]=KDE-ov interfejs za MPlayer +Comment[sv]=KDE-gränssnitt för Mplayer +Comment[ta]=எம் இயக்கிக்கான கேடீஇ இடைமுகம் +Comment[th]=ระบบติดต่อผู้ใช้แบบ KDE ของ MPlayer +Comment[tr]=MPlayer için KDE arayüzü +Comment[uk]=Інтерфейс KDE для MPlayer +Comment[xx]=xxKDE interface for MPlayerxx +Comment[zh_CN]=MPlayer 的 KDE 界面 +Comment[zh_TW]=Mplayer 的 KDE 介面 +Terminal=false +Name=KMPlayer +Name[hi]=केएमप्लेयर +Name[hu]=KMPLayer +Name[sv]=Kmplayer +Name[ta]=கேஎம்இயக்கி +Name[xx]=xxKMPlayerxx +MimeType=application/ogg;application/smil;application/vnd.ms-asf;application/vnd.rn-realmedia;application/x-kmplayer;application/x-mplayer2;application/x-ogg;application/xspf+xml;video/avi;video/mediaplayer;video/mp4;video/mpeg;video/quicktime;video/vnd.rn-realvideo;video/x-avi;video/x-flic;video/x-matroska;video/x-ms-asf;video/x-msvideo;video/x-ms-wmp;video/x-ms-wmv;video/x-ms-wvx;video/x-ogm;video/x-theora;uri/mms;uri/pnm;uri/rtspt;uri/rtspu; +InitialPreference=5 +Categories=Qt;KDE;AudioVideo; +GenericName=Media Player +GenericName[af]=Media Speler +GenericName[ar]= قارئ الوسئط +GenericName[be]=Медыяпрайгравальнік +GenericName[bg]=Медия плеър +GenericName[br]=Soner liesvedia +GenericName[ca]=Reproductor de medis +GenericName[cs]=Přehrávač médií +GenericName[csb]=Òdgrëwôcz lopków wideò +GenericName[cy]=Chwaraeydd Cyfryngau +GenericName[da]=Medieafspiller +GenericName[el]=Αναπαραγωγή πολυμέσων +GenericName[es]=Reproductor multimedia +GenericName[et]=Meediamängija +GenericName[fr]=Lecteur multimédia +GenericName[ga]=Seinnteoir Meán +GenericName[gl]=Reprodutor Multimédia +GenericName[he]=נגן מדיה +GenericName[hi]=मीडिया प्लेयर +GenericName[hu]=Médialejátszó +GenericName[it]=Lettore multimediale +GenericName[ja]=メディアプレーヤ +GenericName[ka]=მედიადამკვრელი +GenericName[lt]=Media grotuvas +GenericName[mk]=Изведувач на мултимедиа +GenericName[nb]=Mediaspiller +GenericName[nl]=Mediaspeler +GenericName[pa]=ਮੀਡਿਆ ਪਲੇਅਰ +GenericName[pt]=Leitor Multimédia +GenericName[pt_BR]=Reprodutor de Mídia +GenericName[ru]=Медиаплеер +GenericName[sk]=Multimediálny prehrávač +GenericName[sr]=Медија плејер +GenericName[sr@Latn]=Medija plejer +GenericName[sv]=Mediaspelare +GenericName[th]=โปรแกรมเล่นสื่อ +GenericName[tr]=Medya Oynatıcı +GenericName[uk]=Аудіо-відео програвач +GenericName[xh]=Umdlali we Midia +GenericName[xx]=xxMedia Playerxx +GenericName[zh_CN]=媒体播放器 +GenericName[zh_TW]=媒體播放程式 +GenericName[zu]=Umdlali Wezezindaba diff --git a/src/kmplayer.h b/src/kmplayer.h new file mode 100644 index 0000000..f2faa92 --- /dev/null +++ b/src/kmplayer.h @@ -0,0 +1,204 @@ +/*************************************************************************** + kmplayer.h - description + ------------------- + begin : Sat Dec 7 16:14:51 CET 2002 + copyright : (C) 2002 by Koos Vriezen + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KMPLAYER_H +#define KMPLAYER_H + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kapp.h> +#include <kmainwindow.h> +#include <kaccel.h> +#include <kaction.h> +#include <kurl.h> +#include "kmplayerplaylist.h" + +static const int id_status_msg = 1; +static const int id_status_timer = 2; + +class QPopupMenu; +class QMenuItem; +class QListViewItem; +class KProcess; +class KMPlayerBroadcastConfig; +class KMPlayerFFServerConfig; +class KSystemTray; + +namespace KMPlayer { + class View; + class PartBase; + class Source; + class KMPlayerDVDSource; + class KMPlayerDVDNavSource; + class KMPlayerVCDSource; + class KMPlayerPipeSource; + class KMPlayerTVSource; + class FFMpeg; + class PlayListItem; +} // namespace + + +class KMPlayerApp : public KMainWindow +{ + Q_OBJECT + +public: + KMPlayerApp (QWidget* parent=0, const char* name=0); + ~KMPlayerApp (); + void openDocumentFile (const KURL& url=KURL()); + void addURL (const KURL& url); + KMPlayer::PartBase * player () const { return m_player; } + void resizePlayer (int percentage); + KDE_NO_EXPORT KRecentFilesAction * recentFiles () const { return fileOpenRecent; } + KDE_NO_EXPORT KMPlayer::View *view () const { return m_view; } + bool broadcasting () const; + void showBroadcastConfig (); + void hideBroadcastConfig (); + KDE_NO_EXPORT KMPlayerBroadcastConfig * broadcastConfig () const { return m_broadcastconfig; } + /* After createGUI() some menu's have to readded again */ + void initMenu (); + void restoreFromConfig (); +protected: + void saveOptions (); + void readOptions (); + void saveProperties (KConfig * config); + void readProperties (KConfig * config); + void initActions (); + void initStatusBar (); + void initView (); + virtual bool queryClose (); + virtual bool queryExit (); + +public slots: + void slotFileNewWindow (); + void slotFileOpen (); + void slotFileOpenRecent (const KURL& url); + void slotSaveAs (); + void slotFileClose (); + void slotFileQuit (); + void slotPreferences (); + void slotViewToolBar (); + void slotViewStatusBar (); + void slotViewMenuBar (); + void slotStatusMsg (const QString &text); + void slotSourceChanged (KMPlayer::Source *, KMPlayer::Source *); +private slots: + void dvdNav (); + void openDVD (); + void openVCD (); + void openAudioCD (); + void openPipe (); + void openVDR (); + void fullScreen (); + void configChanged (); + void keepSizeRatio (); + void startArtsControl(); + void loadingProgress (int percentage); + void positioned (int pos, int length); + void zoom50 (); + void zoom100 (); + void zoom150 (); + void editMode (); + void syncEditMode (); + void broadcastClicked (); + void broadcastStarted (); + void broadcastStopped (); + void playerStarted (); + void slotMinimalMode (); + void slotConfigureKeys(); + void slotConfigureToolbars (); + void slotClearHistory (); + void windowVideoConsoleToggled (int wt); + void playListItemSelected (QListViewItem *); + void playListItemDropped (QDropEvent * e, QListViewItem * after); + void playListItemMoved (); + void menuDropInList (); + void menuDropInGroup (); + void menuCopyDrop (); + void menuDeleteNode (); + void menuMoveUpNode (); + void menuMoveDownNode (); + void preparePlaylistMenu (KMPlayer::PlayListItem *, QPopupMenu *); + +private: + void menuItemClicked (QPopupMenu * menu, int id); + void minimalMode (bool deco=true); + KConfig * config; + KSystemTray * m_systray; + KMPlayer::PartBase * m_player; + KMPlayer::View * m_view; + KMPlayer::NodePtr recents; + KMPlayer::NodePtr playlist; + KMPlayer::NodePtrW manip_node; + + KAction * fileNewWindow; + KAction * fileOpen; + KRecentFilesAction * fileOpenRecent; + KAction * fileClose; + KAction * fileQuit; + KAction * editVolumeInc; + KAction * editVolumeDec; + KAction * toggleView; + KAction * viewSyncEditMode; +#if KDE_IS_VERSION(3,1,90) + KToggleAction * viewFullscreen; +#else + KAction * viewFullscreen; +#endif + KToggleAction * viewEditMode; + KToggleAction * viewToolBar; + KToggleAction * viewStatusBar; + KToggleAction * viewMenuBar; + KToggleAction * viewKeepRatio; + QMenuItem * m_sourcemenu; + QPopupMenu * m_dvdmenu; + QPopupMenu * m_dvdnavmenu; + QPopupMenu * m_vcdmenu; + QPopupMenu * m_audiocdmenu; + QPopupMenu * m_tvmenu; + QPopupMenu * m_dropmenu; + KMPlayerFFServerConfig * m_ffserverconfig; + KMPlayerBroadcastConfig * m_broadcastconfig; + QCString m_dcopName; + KURL::List m_drop_list; + QListViewItem * m_drop_after; + int edit_tree_id; + int manip_tree_id; + int last_time_left; + int recents_id; + int playlist_id; + bool m_showToolbar; + bool m_showStatusbar; + bool m_showMenubar; + bool m_played_intro; + bool m_played_exit; + bool m_minimal_mode; + bool m_auto_resize; +}; + +class KMPLAYER_NO_EXPORT FileDocument : public KMPlayer::Document { +public: + FileDocument (short id, const QString &, KMPlayer::PlayListNotify * notify = 0L); + KMPlayer::NodePtr childFromTag (const QString & tag); + void readFromFile (const QString & file); + void writeToFile (const QString & file); +}; + +#endif // KMPLAYER_H diff --git a/src/kmplayer_asx.cpp b/src/kmplayer_asx.cpp new file mode 100644 index 0000000..9ab333a --- /dev/null +++ b/src/kmplayer_asx.cpp @@ -0,0 +1,146 @@ +/** + * Copyright (C) 2005 by Koos Vriezen <[email protected]> + * + * 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 <config.h> +#include <kdebug.h> +#include <kurl.h> + +#include "kmplayer_asx.h" + +using namespace KMPlayer; + +static QString getAsxAttribute (Element * e, const QString & attr) { + for (AttributePtr a = e->attributes ()->first (); a; a = a->nextSibling ()) + if (attr == a->name ().toString ().lower ()) + return a->value (); + return QString (); +} + +KDE_NO_EXPORT NodePtr ASX::Asx::childFromTag (const QString & tag) { + const char * name = tag.latin1 (); + if (!strcasecmp (name, "entry")) + return new ASX::Entry (m_doc); + else if (!strcasecmp (name, "entryref")) + return new ASX::EntryRef (m_doc); + else if (!strcasecmp (name, "title")) + return new DarkNode (m_doc, name, id_node_title); + else if (!strcasecmp (name, "base")) + return new DarkNode (m_doc, name, id_node_base); + else if (!strcasecmp (name, "param")) + return new DarkNode (m_doc, name, id_node_param); + return 0L; +} + +KDE_NO_EXPORT Node::PlayType ASX::Asx::playType () { + if (cached_ismrl_version != document ()->m_tree_version) + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e->id == id_node_title) + pretty_name = e->innerText ().simplifyWhiteSpace (); + else if (e->id == id_node_base) + src = getAsxAttribute (convertNode <Element> (e), "href"); + } + return Mrl::playType (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT NodePtr ASX::Entry::childFromTag (const QString & tag) { + const char * name = tag.latin1 (); + if (!strcasecmp (name, "ref")) + return new ASX::Ref (m_doc); + else if (!strcasecmp (name, "title")) + return new DarkNode (m_doc, name, id_node_title); + else if (!strcasecmp (name, "base")) + return new DarkNode (m_doc, name, id_node_base); + else if (!strcasecmp (name, "param")) + return new DarkNode (m_doc, name, id_node_param); + else if (!strcasecmp (name, "starttime")) + return new DarkNode (m_doc, name, id_node_starttime); + else if (!strcasecmp (name, "duration")) + return new DarkNode (m_doc, name, id_node_duration); + return 0L; +} + +KDE_NO_EXPORT Node::PlayType ASX::Entry::playType () { + if (cached_ismrl_version != document ()->m_tree_version) { + ref_child_count = 0; + NodePtr ref; + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + switch (e->id) { + case id_node_title: + pretty_name = e->innerText (); // already normalized (hopefully) + break; + case id_node_base: + src = getAsxAttribute (convertNode <Element> (e), "href"); + break; + case id_node_ref: + ref = e; + ref_child_count++; + } + } + if (ref_child_count == 1 && !pretty_name.isEmpty ()) + convertNode <ASX::Ref> (ref)->pretty_name = pretty_name; + cached_ismrl_version = document()->m_tree_version; + } + return play_type_none; +} + +KDE_NO_EXPORT void ASX::Entry::activate () { + resolved = true; + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->id == id_node_param) { + Element * elm = convertNode <Element> (e); + if (getAsxAttribute(elm,"name").lower() == QString("clipsummary")) { + PlayListNotify * n = document ()->notify_listener; + if (n) + n->setInfoMessage (KURL::decode_string ( + getAsxAttribute (elm, "value"))); + break; + } + } + Mrl::activate (); +} + +KDE_NO_EXPORT void ASX::Entry::deactivate () { + PlayListNotify * n = document ()->notify_listener; + if (n) + n->setInfoMessage (QString ()); +} + +KDE_NO_EXPORT bool ASX::Entry::expose () const { + return ref_child_count > 1 && !pretty_name.isEmpty (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void ASX::Ref::opened () { + src = getAsxAttribute (this, "href"); + //kdDebug () << "Ref attr found src: " << src << endl; +} + +KDE_NO_EXPORT bool ASX::Ref::expose () const { + return !src.isEmpty (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void ASX::EntryRef::opened () { + src = getAsxAttribute (this, "href"); + //kdDebug () << "EntryRef attr found src: " << src << endl; +} + diff --git a/src/kmplayer_asx.h b/src/kmplayer_asx.h new file mode 100644 index 0000000..bfdbd7f --- /dev/null +++ b/src/kmplayer_asx.h @@ -0,0 +1,101 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2005 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYER_ASX_H_ +#define _KMPLAYER_ASX_H_ + +#include <qstring.h> + +#include "kmplayerplaylist.h" + +namespace KMPlayer { + +namespace ASX { + +const short id_node_asx = 400; +const short id_node_entry = 401; +const short id_node_ref = 402; +const short id_node_entryref = 403; +const short id_node_title = 404; +const short id_node_base = 405; +const short id_node_param = 406; +const short id_node_starttime = 407; +const short id_node_duration = 408; + +/** + * '<ASX>' tag + */ +class KMPLAYER_NO_EXPORT Asx : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Asx (NodePtr & d) : Mrl (d, id_node_asx) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "ASX"; } + bool expose () const { return !pretty_name.isEmpty (); } + PlayType playType (); +}; + +/** + * Entry tag as found in ASX for playlist item + */ +class KMPLAYER_NO_EXPORT Entry : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Entry (NodePtr & d) + : Mrl (d, id_node_entry), ref_child_count (0) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "Entry"; } + /** + * False, but since we might have a 'base' child, we can have a rel. src + */ + PlayType playType (); + void activate (); + void deactivate (); + bool expose () const; + int ref_child_count; +}; + +/** + * Ref tag as found in ASX for URL item in playlist item + */ +class KMPLAYER_NO_EXPORT Ref : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Ref (NodePtr & d) : Mrl (d, id_node_ref) {} + //NodePtr childFromTag (const QString & tag); + void opened (); + KDE_NO_EXPORT const char * nodeName () const { return "Ref"; } + bool expose () const; +}; + +/** + * EntryRef tag as found in ASX for shortcut of Entry plus Ref playlist item + */ +class KMPLAYER_NO_EXPORT EntryRef : public Mrl { +public: + KDE_NO_CDTOR_EXPORT EntryRef (NodePtr & d) : Mrl (d, id_node_entryref) {} + //NodePtr childFromTag (const QString & tag); + void opened (); + KDE_NO_EXPORT const char * nodeName () const { return "EntryRef"; } +}; + +} //namespace ASX + + +} // namespace KMPlayer + +#endif //_KMPLAYER_ASX_H_ diff --git a/src/kmplayer_atom.cpp b/src/kmplayer_atom.cpp new file mode 100644 index 0000000..da79902 --- /dev/null +++ b/src/kmplayer_atom.cpp @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2005-2006 by Koos Vriezen <[email protected]> + * + * 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 <config.h> +#include <kdebug.h> +#include "kmplayer_atom.h" + +using namespace KMPlayer; + +NodePtr ATOM::Feed::childFromTag (const QString & tag) { + if (!strcmp (tag.latin1 (), "entry")) + return new ATOM::Entry (m_doc); + else if (!strcmp (tag.latin1 (), "link")) + return new ATOM::Link (m_doc); + else if (!strcmp (tag.latin1 (), "title")) + return new DarkNode (m_doc, tag, id_node_title); + return 0L; +} + +void ATOM::Feed::closed () { + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->id == id_node_title) { + pretty_name = c->innerText ().simplifyWhiteSpace (); + break; + } +} + +NodePtr ATOM::Entry::childFromTag (const QString & tag) { + if (!strcmp (tag.latin1 (), "link")) + return new ATOM::Link (m_doc); + else if (!strcmp (tag.latin1 (), "content")) + return new ATOM::Content (m_doc); + else if (!strcmp (tag.latin1 (), "title")) + return new DarkNode (m_doc, tag, id_node_title); + else if (!strcmp (tag.latin1 (), "summary")) + return new DarkNode (m_doc, tag, id_node_summary); + return 0L; +} + +void ATOM::Entry::closed () { + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->id == id_node_title) { + pretty_name = c->innerText ().simplifyWhiteSpace (); + break; + } +} + +Node::PlayType ATOM::Link::playType () { + return src.isEmpty () ? play_type_none : play_type_unknown; +} + +void ATOM::Link::closed () { + QString href; + QString rel; + for (AttributePtr a = attributes ()->first (); a; a = a->nextSibling ()) { + if (a->name () == StringPool::attr_href) + href = a->value (); + else if (a->name () == StringPool::attr_title) + pretty_name = a->value (); + else if (a->name () == "rel") + rel = a->value (); + } + if (!href.isEmpty () && rel == QString::fromLatin1 ("enclosure")) + src = href; + else if (pretty_name.isEmpty ()) + pretty_name = href; +} + +void ATOM::Content::closed () { + for (AttributePtr a = attributes ()->first (); a; a = a->nextSibling ()) { + if (a->name () == StringPool::attr_src) + src = a->value (); + else if (a->name () == StringPool::attr_type) { + QString v = a->value ().lower (); + if (v == QString::fromLatin1 ("text")) + mimetype = QString::fromLatin1 ("text/plain"); + else if (v == QString::fromLatin1 ("html")) + mimetype = QString::fromLatin1 ("text/html"); + else if (v == QString::fromLatin1 ("xhtml")) + mimetype = QString::fromLatin1 ("application/xhtml+xml"); + else + mimetype = v; + } + } +} + +Node::PlayType ATOM::Content::playType () { + if (!hasChildNodes () && !src.isEmpty ()) + return play_type_unknown; + return play_type_none; +} + diff --git a/src/kmplayer_atom.h b/src/kmplayer_atom.h new file mode 100644 index 0000000..b121ead --- /dev/null +++ b/src/kmplayer_atom.h @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2005-2006 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYER_ATOM_H_ +#define _KMPLAYER_ATOM_H_ + +#include <qstringlist.h> + +#include "kmplayerplaylist.h" + +namespace KMPlayer { + +namespace ATOM { + +const short id_node_feed = 300; +const short id_node_entry = 301; +const short id_node_link = 302; +const short id_node_title = 303; +const short id_node_summary = 304; +const short id_node_content = 305; + +/** + * '<feed>' tag + */ +class KMPLAYER_NO_EXPORT Feed : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Feed (NodePtr & d) : Mrl (d, id_node_feed) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "feed"; } + void closed (); + bool expose () const { return !pretty_name.isEmpty (); } +}; + +class KMPLAYER_NO_EXPORT Entry : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Entry (NodePtr & d) : Mrl (d, id_node_entry) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "entry"; } + PlayType playType () { return play_type_none; } + void closed (); +}; + +class KMPLAYER_NO_EXPORT Link : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Link (NodePtr & d) : Mrl (d, id_node_link) {} + KDE_NO_EXPORT const char * nodeName () const { return "link"; } + PlayType playType (); + void closed (); +}; + +class KMPLAYER_NO_EXPORT Content : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Content (NodePtr &d) : Mrl(d, id_node_content) {} + KDE_NO_EXPORT const char * nodeName () const { return "content"; } + PlayType playType (); + void closed (); + //bool expose () const { return isPlayable (); } +}; + +} //namespace ATOM + + +} // namespace KMPlayer + +#endif //_KMPLAYER_ATOM_H_ diff --git a/src/kmplayer_backend.h b/src/kmplayer_backend.h new file mode 100644 index 0000000..242ee32 --- /dev/null +++ b/src/kmplayer_backend.h @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef _KMPLAYER_BACKEND_H_ +#define _KMPLAYER_BACKEND_H_ + +#include <dcopobject.h> + +namespace KMPlayer { + +class BackendPrivate; + +class Backend : public DCOPObject { + K_DCOP +public: + Backend (); + virtual ~Backend (); +k_dcop: + virtual ASYNC setURL (QString url); + virtual ASYNC setSubTitleURL (QString url); + virtual ASYNC play (int repeat_count); + virtual ASYNC stop (); + virtual ASYNC pause (); + /* seek (pos, abs) seek position in deci-seconds */ + virtual ASYNC seek (int pos, bool absolute); + virtual ASYNC hue (int h, bool absolute); + virtual ASYNC saturation (int s, bool absolute); + virtual ASYNC contrast (int c, bool absolute); + virtual ASYNC brightness (int b, bool absolute); + virtual ASYNC volume (int v, bool absolute); + virtual ASYNC frequency (int f); + virtual ASYNC quit (); + virtual ASYNC setConfig (QByteArray); + virtual ASYNC setAudioLang (int, QString); + virtual ASYNC setSubtitle (int, QString); + virtual bool isPlaying (); +private: + BackendPrivate * d; +}; + +} // namespace + +#endif //_KMPLAYER_BACKEND_H_ diff --git a/src/kmplayer_callback.h b/src/kmplayer_callback.h new file mode 100644 index 0000000..45d4f88 --- /dev/null +++ b/src/kmplayer_callback.h @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef _KMPLAYER_CALLBACK_H_ +#define _KMPLAYER_CALLBACK_H_ + +#include <dcopobject.h> +#include <qstringlist.h> + +namespace KMPlayer { + +class CallbackProcess; + +class Callback : public DCOPObject { + K_DCOP +public: + enum StatusCode { stat_addurl = 0, stat_newtitle, stat_hasvideo }; + Callback (CallbackProcess *); +k_dcop: + ASYNC statusMessage (int code, QString msg); + ASYNC errorMessage (int code, QString msg); + ASYNC subMrl (QString mrl, QString title); + ASYNC finished (); + ASYNC playing (); + ASYNC started (QCString dcopname, QByteArray data); + ASYNC movieParams (int length, int width, int height, float aspect, QStringList alang, QStringList slang); + ASYNC moviePosition (int position); + ASYNC loadingProgress (int percentage); + ASYNC toggleFullScreen (); +private: + CallbackProcess * m_process; +}; + +} // namespace + +#endif //_KMPLAYER_CALLBACK_H_ diff --git a/src/kmplayer_def.h b/src/kmplayer_def.h new file mode 100644 index 0000000..7c3ee7f --- /dev/null +++ b/src/kmplayer_def.h @@ -0,0 +1,69 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2006 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * until boost gets common, a more or less compatable one .. + */ + +#ifndef _KMPLAYER_DEF_H_ +#define _KMPLAYER_DEF_H_ + +#include <config.h> +#ifndef ASSERT +#define ASSERT Q_ASSERT +#endif + +#include <kdemacros.h> + +#undef KDE_NO_CDTOR_EXPORT +#undef KDE_NO_EXPORT +#ifndef KDE_EXPORT + #define KDE_EXPORT +#endif +#if __GNUC__ - 0 > 3 && __GNUC_MINOR__ - 0 > 1 +# define KMPLAYER_NO_EXPORT __attribute__ ((visibility("hidden"))) +# define KMPLAYER_EXPORT __attribute__ ((visibility("default"))) +# define KMPLAYER_NO_MBR_EXPORT __attribute__ ((visibility("hidden"))) +# define KDE_NO_CDTOR_EXPORT +# define KDE_NO_EXPORT +#elif __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 > 3) + #if __GNUC__ - 0 > 3 + #define KMPLAYER_NO_EXPORT __attribute__ ((visibility("hidden"))) + #else + #define KMPLAYER_NO_EXPORT + #endif + #define KDE_NO_CDTOR_EXPORT __attribute__ ((visibility("hidden"))) + #define KDE_NO_EXPORT __attribute__ ((visibility("hidden"))) + #define KMPLAYER_EXPORT __attribute__ ((visibility("default"))) + #define KMPLAYER_NO_MBR_EXPORT +#elif __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 > 2) + #define KDE_NO_CDTOR_EXPORT + #define KDE_NO_EXPORT __attribute__ ((visibility("hidden"))) + #define KMPLAYER_EXPORT + #define KMPLAYER_NO_EXPORT + #define KMPLAYER_NO_MBR_EXPORT +#else + #define KDE_NO_CDTOR_EXPORT + #define KDE_NO_EXPORT + #define KMPLAYER_EXPORT + #define KMPLAYER_NO_EXPORT + #define KMPLAYER_NO_MBR_EXPORT +#endif + + +#endif //_KMPLAYER_DEF_H_ diff --git a/src/kmplayer_koffice.desktop b/src/kmplayer_koffice.desktop new file mode 100644 index 0000000..faff60e --- /dev/null +++ b/src/kmplayer_koffice.desktop @@ -0,0 +1,15 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=KMPlayer +Name[hi]=केएमप्लेयर +Name[hu]=KMPLayer +Name[sv]=Kmplayer +Name[ta]=கேஎம்இயக்கி +Name[xx]=xxKMPlayerxx +X-KDE-Library=libkmplayerkofficepart +MimeType=application/ogg;application/smil;application/vnd.ms-asf;application/vnd.rn-realmedia;application/x-kmplayer;application/x-mplayer2;application/x-ogg;video/avi;video/mediaplayer;video/mp4;video/mpeg;video/quicktime;video/vnd.rn-realvideo;video/x-avi;video/x-flic;video/x-matroska;video/x-ms-asf;video/x-msvideo;video/x-ms-wmp;video/x-ms-wmv;video/x-ogm;video/x-theora;uri/mms;uri/pnm;uri/rtspt;uri/rtspu; +Type=Service +Icon=kmplayer +ServiceTypes=KOfficePart,KParts/ReadOnlyPart,KParts/ReadWritePart,Browser/View,KMediaPlayer/Player +X-KDE-NativeMimeType=application/x-kmplayer +InitialPreference=5 diff --git a/src/kmplayer_koffice_part.cpp b/src/kmplayer_koffice_part.cpp new file mode 100644 index 0000000..756402a --- /dev/null +++ b/src/kmplayer_koffice_part.cpp @@ -0,0 +1,168 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <signal.h> + +#include <qapplication.h> +#include <qcstring.h> +#include <qtimer.h> +#include <qmultilineedit.h> +#include <qpushbutton.h> +#include <qpopupmenu.h> +#include <qslider.h> +#include <qvaluelist.h> + +#include <kprocess.h> +#include <kmessagebox.h> +#include <kaboutdata.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kaction.h> +#include <kstandarddirs.h> +#include <kparts/factory.h> + +#include "kmplayerpartbase.h" +#include "kmplayer_koffice_part.h" +#include "kmplayerview.h" +#include "kmplayerconfig.h" + +#ifdef HAVE_KOFFICE + +#include <qdom.h> +//#include <qmetaobject.h> +#include <qlayout.h> +#include <qptrlist.h> +#include <qpainter.h> +#include <koFrame.h> + +class KMPlayerFactory : public KParts::Factory { +public: + KMPlayerFactory (); + virtual ~KMPlayerFactory (); + virtual KParts::Part *createPartObject + (QWidget *wparent, const char *wname, QObject *parent, const char *name, + const char *className, const QStringList &args); + static KInstance * instance () { return s_instance; } +private: + static KInstance * s_instance; +}; + +K_EXPORT_COMPONENT_FACTORY (libkmplayerkofficepart, KMPlayerFactory) + +KInstance *KMPlayerFactory::s_instance = 0; + +KMPlayerFactory::KMPlayerFactory () { + s_instance = new KInstance ("KMPlayerKofficePart"); +} + +KMPlayerFactory::~KMPlayerFactory () { + delete s_instance; +} + +KParts::Part *KMPlayerFactory::createPartObject + (QWidget *wparent, const char *wname, + QObject *parent, const char * name, + const char * cls, const QStringList & args) { + if (strstr (cls, "KoDocument")) + return new KOfficeMPlayer (wparent, wname, parent, name); + return 0L; +} + +//----------------------------------------------------------------------------- + + +KOfficeMPlayer::KOfficeMPlayer (QWidget *parentWidget, const char *widgetName, QObject* parent, const char* name, bool singleViewMode) + : KoDocument (parentWidget, widgetName, parent, name, singleViewMode), + m_config (new KConfig ("kmplayerrc")), + m_player (new KMPlayer (parentWidget, 0L, 0L, 0L, m_config)) +{ + setInstance (KMPlayerFactory::instance (), false); + setReadWrite (false); + m_player->init(); + m_player->setSource (m_player->sources () ["urlsource"]); + //setWidget (view); +} + +KOfficeMPlayer::~KOfficeMPlayer () { + kdDebug() << "KOfficeMPlayer::~KOfficeMPlayer" << /*kdBacktrace() <<*/ endl; +} + +void KOfficeMPlayer::paintContent (QPainter& p, const QRect& r, bool, double, double) { + p.fillRect (r, QBrush (QColor (0, 0, 0))); +} + +bool KOfficeMPlayer::initDoc() { + kdDebug() << "KOfficeMPlayer::initDoc" << endl; + return true; +} + +bool KOfficeMPlayer::loadXML (QIODevice *, const QDomDocument & doc) { + QDomNode node = doc.firstChild (); + if (node.isNull ()) return true; + kdDebug() << "KOfficeMPlayer::loadXML " << node.nodeName () << endl; + node = node.firstChild (); + if (node.isNull ()) return true; + kdDebug() << "KOfficeMPlayer::loadXML " << node.nodeName () << endl; + node = node.firstChild (); + if (node.isNull () || !node.isText ()) return true; + m_player->setURL (KURL (node.toText ().data ())); + return true; +} + +bool KOfficeMPlayer::loadOasis (const QDomDocument &, KoOasisStyles &, const QDomDocument &, KoStore *) { + return true; +} + +QDomDocument KOfficeMPlayer::saveXML() { + QDomDocument doc = createDomDocument ("kmplayer", QString::number(1.0)); + QDomElement docelm = doc.documentElement(); + docelm.setAttribute ("editor", "KMPlayer"); + docelm.setAttribute ("mime", "application/x-kmplayer"); + QDomElement url = doc.createElement ("url"); + url.appendChild (doc.createTextNode (m_player->url ().url ())); + doc.appendChild (url); + return doc; +} + +KoView* KOfficeMPlayer::createViewInstance (QWidget* parent, const char* name) { + kdDebug() << "KOfficeMPlayer::createViewInstance" << endl; + return new KOfficeMPlayerView (this, parent); +} + +KOfficeMPlayerView::KOfficeMPlayerView (KOfficeMPlayer* part, QWidget* parent, const char* name) + : KoView (part, parent, name), + m_view (static_cast <KMPlayer::View*> (part->player ()->view ())) { + kdDebug() << "KOfficeMPlayerView::KOfficeMPlayerView this:" << this << " parent:" << parent << endl; + m_oldparent = static_cast <QWidget*> (m_view->parent()); + m_view->reparent (this, QPoint (0, 0)); + QVBoxLayout * box = new QVBoxLayout (this, 0, 0); + box->addWidget (m_view); +} + +KOfficeMPlayerView::~KOfficeMPlayerView () { + kdDebug() << "KOfficeMPlayerView::~KOfficeMPlayerView this:" << this << endl; + m_view->reparent (m_oldparent, QPoint (0, 0)); +} + +#include "kmplayer_koffice_part.moc" +#endif diff --git a/src/kmplayer_koffice_part.h b/src/kmplayer_koffice_part.h new file mode 100644 index 0000000..632a570 --- /dev/null +++ b/src/kmplayer_koffice_part.h @@ -0,0 +1,85 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef KMPLAYER_KOFFICE_PART_H +#define KMPLAYER_KOFFICE_PART_H + +#include <config.h> +#include <kmediaplayer/player.h> +#include <kparts/browserextension.h> +#include <kparts/factory.h> +#include <kurl.h> +#ifdef HAVE_KOFFICE +#include <koDocument.h> +#include <koView.h> +#endif //HAVE_KOFFICE +#include <qobject.h> +#include <qvaluelist.h> +#include <qstringlist.h> +#include <qguardedptr.h> +#include <qregexp.h> +#include "kmplayerview.h" +#include "kmplayersource.h" + + +class KProcess; +class KAboutData; +class KMPlayer; +class KInstance; +class KConfig; +class QIODevice; + +#ifdef HAVE_KOFFICE +class KOfficeMPlayer; + +class KOfficeMPlayerView : public KoView { + Q_OBJECT +public: + KOfficeMPlayerView (KOfficeMPlayer* part, QWidget* parent, const char* name = 0 ); + ~KOfficeMPlayerView (); + void updateReadWrite(bool) {} +private: + KMPlayer::View * m_view; + QGuardedPtr <QWidget> m_oldparent; +}; + +class KOfficeMPlayer : public KoDocument { + Q_OBJECT +public: + KOfficeMPlayer (QWidget *parentWidget = 0, const char *widgetName = 0, QObject* parent = 0, const char* name = 0, bool singleViewMode = false); + ~KOfficeMPlayer (); + + virtual void paintContent (QPainter& painter, const QRect& rect, + bool transparent = false, double zoomX = 1.0, double zoomY = 1.0); + virtual bool initDoc (); + virtual bool loadXML (QIODevice *, const QDomDocument &); + virtual bool loadOasis (const QDomDocument &, KoOasisStyles &, const QDomDocument &, KoStore *); + virtual QDomDocument saveXML (); + virtual QCString mimeType() const { return "application/x-kmplayer"; } + + KMPlayer * player () const { return m_player; } +protected: + virtual KoView* createViewInstance (QWidget* parent, const char* name); +private: + KConfig * m_config; + KMPlayer * m_player; + KOfficeMPlayerView * m_view; +}; +#endif //HAVE_KOFFICE + +#endif diff --git a/src/kmplayer_part.cpp b/src/kmplayer_part.cpp new file mode 100644 index 0000000..74698b9 --- /dev/null +++ b/src/kmplayer_part.cpp @@ -0,0 +1,1197 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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 <list> +#include <algorithm> + +#include <config.h> +#include <qpopupmenu.h> +#include <qtimer.h> +#include <qpushbutton.h> +#include <qslider.h> + +class KXMLGUIClient; // workaround for kde3.3 on sarge with gcc4, kactioncollection.h does not forward declare KXMLGUIClient +#include <klibloader.h> +#include <kdebug.h> +#include <kconfig.h> +#include <ksimpleconfig.h> +#include <kaction.h> +#include <kapplication.h> +#include <klocale.h> +#include <kinstance.h> +#include <kparts/factory.h> +#include <kstaticdeleter.h> +#include <kstatusbar.h> + +#include "kmplayer_part.h" +#include "kmplayerview.h" +#include "viewarea.h" +#include "kmplayercontrolpanel.h" +#include "kmplayerconfig.h" +#include "kmplayerprocess.h" + +using namespace KMPlayer; + +typedef std::list <KMPlayerPart *> KMPlayerPartList; + +struct KMPLAYER_NO_EXPORT KMPlayerPartStatic { + KMPlayerPartStatic (); + ~KMPlayerPartStatic (); + KMPlayerPartList partlist; +}; + +static KMPlayerPartStatic * kmplayerpart_static = 0L; + +KDE_NO_CDTOR_EXPORT KMPlayerPartStatic::KMPlayerPartStatic () { + StringPool::init (); +} + +KDE_NO_CDTOR_EXPORT KMPlayerPartStatic::~KMPlayerPartStatic () { + kmplayerpart_static = 0L; + StringPool::reset (); + // delete map content +} + +struct KMPLAYER_NO_EXPORT GroupPredicate { + const KMPlayerPart * m_part; + const QString & m_group; + bool m_get_any; + GroupPredicate(const KMPlayerPart *part, const QString &group, bool b=false) + : m_part (part), m_group (group), m_get_any (b) {} + bool operator () (const KMPlayerPart * part) const { + return ((m_get_any && part != m_part && + !part->master () && !part->url ().isEmpty ()) || + (m_part->allowRedir (part->m_docbase) && + (part->m_group == m_group || + part->m_group == QString::fromLatin1("_master") || + m_group == QString::fromLatin1("_master")) && + (part->m_features & KMPlayerPart::Feat_Viewer) != + (m_part->m_features & KMPlayerPart::Feat_Viewer))); + } +}; + +static KStaticDeleter <KMPlayerPartStatic> kmplayerpart_staticdeleter; + +//----------------------------------------------------------------------------- + +class KMPlayerFactory : public KParts::Factory { +public: + KMPlayerFactory (); + virtual ~KMPlayerFactory (); + virtual KParts::Part *createPartObject + (QWidget *wparent, const char *wname, + QObject *parent, const char *name, + const char *className, const QStringList &args); + static KInstance * instance () { return s_instance; } +private: + static KInstance * s_instance; +}; + +K_EXPORT_COMPONENT_FACTORY (libkmplayerpart, KMPlayerFactory) + +KInstance *KMPlayerFactory::s_instance = 0; + +KDE_NO_CDTOR_EXPORT KMPlayerFactory::KMPlayerFactory () { + s_instance = new KInstance ("kmplayer"); +} + +KDE_NO_CDTOR_EXPORT KMPlayerFactory::~KMPlayerFactory () { + delete s_instance; +} + +KDE_NO_EXPORT KParts::Part *KMPlayerFactory::createPartObject + (QWidget *wparent, const char *wname, + QObject *parent, const char * name, + const char * cls, const QStringList & args) { + kdDebug() << "KMPlayerFactory::createPartObject " << cls << endl; + return new KMPlayerPart (wparent, wname, parent, name, args); +} + +//----------------------------------------------------------------------------- + +static bool getBoolValue (const QString & value) { + return (value.lower() != QString::fromLatin1("false") && + value.lower() != QString::fromLatin1("off") && + value.lower() != QString::fromLatin1("0")); +} + +#define SET_FEAT_ON(f) { m_features |= f; turned_off_features &= ~f; } +#define SET_FEAT_OFF(f) { m_features &= ~f; turned_off_features |= f; } + +KDE_NO_CDTOR_EXPORT KMPlayerPart::KMPlayerPart (QWidget * wparent, const char *wname, + QObject * parent, const char *name, const QStringList &args) + : PartBase (wparent, wname, parent, name, new KConfig ("kmplayerrc")), + m_master (0L), + m_browserextension (new KMPlayerBrowserExtension (this)), + m_liveconnectextension (new KMPlayerLiveConnectExtension (this)), + m_features (Feat_Unknown), + m_started_emited (false), + m_havehref (false) { + kdDebug () << "KMPlayerPart(" << this << ")::KMPlayerPart ()" << endl; + bool show_fullscreen = false; + if (!kmplayerpart_static) + kmplayerpart_static = kmplayerpart_staticdeleter.setObject (new KMPlayerPartStatic ()); + setInstance (KMPlayerFactory::instance (), true); + init (actionCollection ()); + m_sources ["hrefsource"] = (new KMPlayerHRefSource (this)); +#ifdef HAVE_NSPR + KMPlayer::NpPlayer *npp = (KMPlayer::NpPlayer *) players () ["npp"]; + connect (npp, SIGNAL (evaluate (const QString &, QString &)), + m_liveconnectextension, SLOT (evaluate (const QString &, QString &))); + connect (npp, SIGNAL (openUrl (const KURL &, const QString &)), + m_browserextension, + SLOT (slotRequestOpenURL (const KURL &, const QString &))); +#endif + /*KAction *playact =*/ new KAction(i18n("P&lay"), QString ("player_play"), KShortcut (), this, SLOT(play ()), actionCollection (), "play"); + /*KAction *pauseact =*/ new KAction(i18n("&Pause"), QString ("player_pause"), KShortcut (), this, SLOT(pause ()), actionCollection (), "pause"); + /*KAction *stopact =*/ new KAction(i18n("&Stop"), QString ("player_stop"), KShortcut (), this, SLOT(stop ()), actionCollection (), "stop"); + new KAction (i18n ("Increase Volume"), QString ("player_volume"), KShortcut (), this, SLOT (increaseVolume ()), actionCollection (), "edit_volume_up"); + new KAction (i18n ("Decrease Volume"), QString ("player_volume"), KShortcut (), this, SLOT (decreaseVolume ()), actionCollection (), "edit_volume_down"); + Source * urlsource = m_sources ["urlsource"]; + KMPlayer::ControlPanel * panel = m_view->controlPanel (); + QStringList::const_iterator it = args.begin (); + QStringList::const_iterator end = args.end (); + int turned_off_features = 0; + for ( ; it != end; ++it) { + int equalPos = (*it).find("="); + if (equalPos > 0) { + QString name = (*it).left (equalPos).lower (); + QString value = (*it).right ((*it).length () - equalPos - 1); + if (value.at(0)=='\"') + value = value.right (value.length () - 1); + if (value.at (value.length () - 1) == '\"') + value.truncate (value.length () - 1); + kdDebug () << "name=" << name << " value=" << value << endl; + if (name == "href") { + urlsource->setURL (KURL (value)); + urlsource->setIdentified (false); + m_havehref = true; + } else if (name == QString::fromLatin1("width")) { + m_noresize = true; + } else if (name == QString::fromLatin1("height")) { + m_noresize = true; + } else if (name == QString::fromLatin1("type")) { + urlsource->document ()->mrl ()->mimetype = value; + } else if (name == QString::fromLatin1("controls")) { + //http://service.real.com/help/library/guides/production8/realpgd.htm?src=noref,rnhmpg_080301,rnhmtn,nosrc + //http://service.real.com/help/library/guides/production8/htmfiles/control.htm + QStringList sl = QStringList::split (QChar (','), value); + QStringList::const_iterator it = sl.begin (); + const QStringList::const_iterator e = sl.end (); + for (QStringList::const_iterator i = sl.begin (); i != e; ++i) { + QString val_lower ((*i).lower ()); + if (val_lower == QString::fromLatin1("imagewindow")) { + SET_FEAT_ON (Feat_ImageWindow | Feat_Viewer) + } else if (val_lower == QString::fromLatin1("all")) { + m_features = (Feat_Controls | Feat_StatusBar); + } else if (val_lower == QString::fromLatin1("tacctrl")) { + SET_FEAT_ON (Feat_Label) + } else if (val_lower == QString::fromLatin1("controlpanel")) { + SET_FEAT_ON (Feat_Controls) + } else if (val_lower == QString::fromLatin1("infovolumepanel")){ + SET_FEAT_ON (Feat_Controls) // TODO + } else if (val_lower == QString::fromLatin1("positionfield") || + val_lower == QString::fromLatin1("positionslider")) { + setAutoControls (false); + panel->positionSlider ()->show (); + SET_FEAT_ON (Feat_Controls) + } else if ( val_lower == QString::fromLatin1("homectrl")) { + setAutoControls (false); + panel->button (KMPlayer::ControlPanel::button_config)->show(); + } else if (val_lower == QString::fromLatin1("mutectrl") || + val_lower == QString::fromLatin1("mutevolume")) { + setAutoControls (false); + panel->volumeBar()->setMinimumSize (QSize (20, panel->volumeBar()->minimumSize ().height ())); + panel->volumeBar()->show (); + SET_FEAT_ON (Feat_Controls) + } else if (val_lower == QString::fromLatin1("rwctrl")) { + setAutoControls (false); + panel->button (KMPlayer::ControlPanel::button_back)->show (); // rewind ? + SET_FEAT_ON (Feat_Controls) + } else if ( val_lower == QString::fromLatin1("ffctrl")) { + setAutoControls (false); + panel->button(KMPlayer::ControlPanel::button_forward)->show(); + m_features = Feat_Controls; + } else if ( val_lower ==QString::fromLatin1("stopbutton")) { + setAutoControls (false); + panel->button (KMPlayer::ControlPanel::button_stop)->show (); + SET_FEAT_ON (Feat_Controls) + } else if (val_lower == QString::fromLatin1("playbutton") || + val_lower ==QString::fromLatin1("playonlybutton")) { + setAutoControls (false); + panel->button (KMPlayer::ControlPanel::button_play)->show (); + SET_FEAT_ON (Feat_Controls) + } else if (val_lower ==QString::fromLatin1("pausebutton")) { + setAutoControls (false); + panel->button (KMPlayer::ControlPanel::button_pause)->show (); + SET_FEAT_ON (Feat_Controls) + } else if (val_lower == QString::fromLatin1("statusbar") || + val_lower == QString::fromLatin1("statusfield")) { + SET_FEAT_ON (Feat_StatusBar) + } else if (val_lower == QString::fromLatin1("infopanel")) { + SET_FEAT_ON (Feat_InfoPanel) + } else if (val_lower == QString::fromLatin1("playlist")) { + SET_FEAT_ON (Feat_PlayList) + } else if (val_lower==QString::fromLatin1("volumeslider")) { + SET_FEAT_ON (Feat_VolumeSlider) + setAutoControls (false); + panel->volumeBar()->show (); + panel->volumeBar()->setMinimumSize (QSize (20, panel->volumeBar()->minimumSize ().height ())); + } + } + } else if (name == QString::fromLatin1("uimode")) { + QString val_lower (value.lower ()); + if (val_lower == QString::fromLatin1("full")) + SET_FEAT_ON (Feat_All & ~(Feat_PlayList | Feat_ImageWindow)) + // TODO: invisible, none, mini + } else if (name == QString::fromLatin1("nolabels")) { + SET_FEAT_OFF (Feat_Label) + } else if (name == QString::fromLatin1("nocontrols")) { + SET_FEAT_OFF (Feat_Controls | Feat_VolumeSlider) + } else if (name == QString::fromLatin1("showdisplay")) { + // the author name, the clip name, and the copyright information + if (getBoolValue (value)) + SET_FEAT_ON (Feat_InfoPanel) + else + SET_FEAT_OFF (Feat_InfoPanel) + } else if (name == QString::fromLatin1("showcontrols")) { + if (getBoolValue (value)) + SET_FEAT_ON (Feat_Viewer | Feat_Controls) + else + SET_FEAT_OFF (Feat_Controls | Feat_VolumeSlider) + } else if (name == QString::fromLatin1("showstatusbar")) { + if (getBoolValue (value)) + SET_FEAT_ON (Feat_Viewer | Feat_StatusBar) + else + SET_FEAT_OFF (Feat_StatusBar) + // else showcaptioning/showgotobar/showpositioncontrols/showtracker + } else if (name == QString::fromLatin1("console")) { + m_group = value.isEmpty() ? QString::fromLatin1("_anonymous") : value; + } else if (name == QString::fromLatin1("__khtml__pluginbaseurl")) { + m_docbase = KURL (value); + } else if (name == QString::fromLatin1("src")) { + m_src_url = value; + } else if (name == QString::fromLatin1("filename")) { + m_file_name = value; + } else if (name == QString::fromLatin1 ("fullscreenmode")) { + show_fullscreen = getBoolValue (value); + } else if (name == QString::fromLatin1 ("autostart")) { + urlsource->setAutoPlay (getBoolValue (value)); + } + // volume/clicktoplay/transparentatstart/animationatstart + // autorewind/displaysize/border + if (name.startsWith (QString::fromLatin1 ("__khtml__"))) + name = name.mid (9); + convertNode <KMPlayer::Element> (urlsource->document ())->setAttribute (name, value); + } + } + if (turned_off_features) { + if (m_features == Feat_Unknown) + m_features = (Feat_All & ~(Feat_PlayList | Feat_ImageWindow)); + m_features &= ~turned_off_features; + } + //KParts::Part::setWidget (m_view); + setXMLFile("kmplayerpartui.rc"); + panel->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom50, + this, SLOT (setMenuZoom (int))); + panel->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom100, + this, SLOT (setMenuZoom (int))); + panel->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom150, + this, SLOT (setMenuZoom (int))); + + m_view->setNoInfoMessages (m_features != Feat_InfoPanel); + if (m_features == Feat_InfoPanel) + m_view->setInfoPanelOnly (); + else if (m_features == Feat_PlayList) + m_view->setPlaylistOnly (); + else { + if (m_features & Feat_StatusBar) + m_view->setStatusBarMode (KMPlayer::View::SB_Show); + if (m_features & (Feat_Controls | Feat_VolumeSlider)) + m_view->setControlPanelMode (m_features & Feat_Viewer ? KMPlayer::View::CP_Show : KMPlayer::View::CP_Only); + else if (m_features & Feat_ImageWindow) + m_view->setControlPanelMode (KMPlayer::View::CP_Hide); + else + m_view->setControlPanelMode (KMPlayer::View::CP_AutoHide); + } + bool group_member = !m_group.isEmpty () && m_group != QString::fromLatin1("_unique") && m_features != Feat_Unknown; + if (!group_member || m_features & Feat_Viewer) { + // not part of a group or we're the viewer + setProcess ("mplayer"); + setRecorder ("mencoder"); + connectPanel (m_view->controlPanel ()); + if (m_features & Feat_StatusBar) { + last_time_left = 0; + connect (this, SIGNAL (positioned (int, int)), + this, SLOT (statusPosition (int, int))); + m_view->statusBar ()->insertItem (QString ("--:--"), 1, 0, true); + } + } + if (group_member) { + KMPlayerPartList::iterator i =kmplayerpart_static->partlist.begin (); + KMPlayerPartList::iterator e =kmplayerpart_static->partlist.end (); + GroupPredicate pred (this, m_group); + for (i = std::find_if (i, e, pred); + i != e; + i = std::find_if (++i, e, pred)) { + // found viewer and control part, exchange players now + KMPlayerPart * vp = (m_features & Feat_Viewer) ? this : *i; + KMPlayerPart * cp = (m_features & Feat_Viewer) ? *i : this; + setProcess ("mplayer"); + cp->connectToPart (vp); + } + } else + m_group.truncate (0); + kmplayerpart_static->partlist.push_back (this); + + QWidget *pwidget = view ()->parentWidget (); + if (pwidget) { + m_view->viewArea()->setPaletteBackgroundColor(pwidget->paletteBackgroundColor ()); + m_view->viewer()->setBackgroundColor(pwidget->paletteBackgroundColor()); + } + + if (m_view->isFullScreen () != show_fullscreen) + m_view->fullScreen (); +} + +#undef SET_FEAT_ON +#undef SET_FEAT_OFF + +KDE_NO_CDTOR_EXPORT KMPlayerPart::~KMPlayerPart () { + kdDebug() << "KMPlayerPart::~KMPlayerPart" << endl; + //if (!m_group.isEmpty ()) { + KMPlayerPartList::iterator i = std::find (kmplayerpart_static->partlist.begin (), kmplayerpart_static->partlist.end (), this); + if (i != kmplayerpart_static->partlist.end ()) + kmplayerpart_static->partlist.erase (i); + else + kdError () << "KMPlayerPart::~KMPlayerPart group lost" << endl; + //} + delete m_config; + m_config = 0L; +} + +KDE_NO_EXPORT bool KMPlayerPart::allowRedir (const KURL & url) const { + return kapp->authorizeURLAction ("redirect", m_docbase, url); +} + +KDE_NO_EXPORT void KMPlayerPart::setAutoControls (bool b) { + m_auto_controls = b; + m_view->controlPanel ()->setAutoControls (b); +} + +KDE_NO_EXPORT void KMPlayerPart::viewerPartDestroyed (QObject * o) { + if (o == m_master) + m_master = 0L; + kdDebug () << "KMPlayerPart(" << this << ")::viewerPartDestroyed" << endl; + const KMPlayerPartList::iterator e =kmplayerpart_static->partlist.end(); + KMPlayerPartList::iterator i = std::find_if (kmplayerpart_static->partlist.begin (), e, GroupPredicate (this, m_group)); + if (i != e && *i != this) + (*i)->updatePlayerMenu (m_view->controlPanel ()); +} + +KDE_NO_EXPORT void KMPlayerPart::viewerPartProcessChanged (const char *) { + const KMPlayerPartList::iterator e =kmplayerpart_static->partlist.end(); + KMPlayerPartList::iterator i = std::find_if (kmplayerpart_static->partlist.begin (), e, GroupPredicate (this, m_group)); + if (i != e && *i != this) + (*i)->updatePlayerMenu (m_view->controlPanel ()); +} + +KDE_NO_EXPORT void KMPlayerPart::viewerPartSourceChanged(Source *o, Source *s) { + kdDebug () << "KMPlayerPart::source changed " << m_master << endl; + if (m_master && m_view) { + connectSource (o, s); + m_master->updatePlayerMenu (m_view->controlPanel ()); + } +} + +KDE_NO_EXPORT bool KMPlayerPart::openURL (const KURL & _url) { + kdDebug () << "KMPlayerPart::openURL " << _url.url() << endl; + Source * urlsource = m_sources ["urlsource"]; + KMPlayerHRefSource * hrefsource = static_cast <KMPlayerHRefSource *>(m_sources ["hrefsource"]); + KMPlayerPartList::iterator i =kmplayerpart_static->partlist.begin (); + KMPlayerPartList::iterator e =kmplayerpart_static->partlist.end (); + GroupPredicate pred (this, m_group); + KURL url; + if (!m_file_name.isEmpty () && (_url.isEmpty () || _url == m_docbase)) + url = KURL (m_docbase, m_file_name); // fix misdetected SRC attr + else if (_url != m_docbase) { + url = _url; + if (!m_file_name.isEmpty () && _url.url ().find (m_file_name) < 0) { + KURL u (m_file_name); + if ((u.protocol () == QString ("mms")) || + _url.protocol ().isEmpty ()) { + // see if we somehow have to merge these + int p = _url.port (); + if (p > 0) + u.setPort (p); + if (u.path ().isEmpty ()) + u.setPath (QChar ('/') + _url.host ()); + if (allowRedir (u)) { + url = u; + kdDebug () << "KMPlayerPart::openURL compose " << m_file_name << " " << _url.url() << " ->" << u.url() << endl; + } + } + } + } else { // if url is the container document, then it's an empty URL + if (m_features & Feat_Viewer) // damn, look in the group + for (i = std::find_if (i, e, pred); + i != e; + i = std::find_if (++i, e, pred)) + if (!(*i)->url ().isEmpty ()) { + url = (*i)->url (); + break; + } + } + if (m_havehref && (!kapp->authorizeURLAction ("redirect", url, urlsource->url ()) || !m_settings->allowhref)) { + m_havehref = false; + url = urlsource->url (); + } + if (!m_havehref) + setURL (url); + if (url.isEmpty ()) { + if (!m_master && !(m_features & Feat_Viewer)) + // no master set, wait for a viewer to attach or timeout + QTimer::singleShot (50, this, SLOT (waitForImageWindowTimeOut ())); + return true; + } + if (!m_group.isEmpty () && !(m_features & Feat_Viewer)) { + // group member, not the image window + for (i = std::find_if (i, e, pred); + i != e; + i = std::find_if (++i, e, pred)) + if ((*i)->url ().isEmpty ()) // image window created w/o url + return (*i)->openURL (_url); + QTimer::singleShot (50, this, SLOT (waitForImageWindowTimeOut ())); + //kdError () << "Not the ImageWindow and no ImageWindow found" << endl; + return true; + } + if (!m_view || !url.isValid ()) return false; + KParts::URLArgs args = m_browserextension->urlArgs(); + if (!args.serviceType.isEmpty ()) + urlsource->document ()->mrl ()->mimetype = args.serviceType; + if (m_havehref && m_settings->allowhref) { + hrefsource->setURL (url); + setSource (hrefsource); + } else { + hrefsource->clear (); + PartBase::openURL (m_havehref ? urlsource->url () : url); + if (urlsource->autoPlay ()) { + emit started (0L); + m_started_emited = true; + } + m_havehref = false; + } + return true; +} + +KDE_NO_EXPORT bool KMPlayerPart::openNewURL (const KURL & url) { + m_file_name.truncate (0); + m_havehref = false; + m_sources ["urlsource"]->setAutoPlay (true); + return openURL (url); +} + +KDE_NO_EXPORT void KMPlayerPart::waitForImageWindowTimeOut () { + if (!m_master) { + // still no ImageWindow attached, eg. audio only + const KMPlayerPartList::iterator e =kmplayerpart_static->partlist.end(); + GroupPredicate pred (this, m_group); + KMPlayerPartList::iterator i = std::find_if (kmplayerpart_static->partlist.begin (), e, pred); + bool noattach = (i == e || *i == this); + if (noattach) { + if (!url ().isEmpty ()) { + m_features |= KMPlayerPart::Feat_Viewer; //hack, become the view + for (i = std::find_if (kmplayerpart_static->partlist.begin (), e, pred); i != e; i = std::find_if (++i, e, pred)) + (*i)->connectToPart (this); + PartBase::openURL (url ()); + } else { // see if we can attach to something out there .. + i = std::find_if (kmplayerpart_static->partlist.begin (), e, GroupPredicate (this, m_group, true)); + noattach = (i == e); + } + } + if (!noattach) + connectToPart (*i); + } +} + +KDE_NO_EXPORT bool KMPlayerPart::closeURL () { + if (!m_group.isEmpty ()) { + kmplayerpart_static->partlist.remove (this); + m_group.truncate (0); + } + return PartBase::closeURL (); +} + +KDE_NO_EXPORT void KMPlayerPart::connectToPart (KMPlayerPart * m) { + m_master = m; + m->connectPanel (m_view->controlPanel ()); + m->updatePlayerMenu (m_view->controlPanel ()); + if (m_features & Feat_PlayList) + m->connectPlaylist (m_view->playList ()); + if (m_features & Feat_InfoPanel) + m->connectInfoPanel (m_view->infoPanel ()); + connectSource (m_source, m->source ()); + connect (m, SIGNAL (destroyed (QObject *)), + this, SLOT (viewerPartDestroyed (QObject *))); + connect (m, SIGNAL (processChanged (const char *)), + this, SLOT (viewerPartProcessChanged (const char *))); + connect (m, SIGNAL (sourceChanged (KMPlayer::Source *, KMPlayer::Source *)), + this, SLOT (viewerPartSourceChanged (KMPlayer::Source *, KMPlayer::Source *))); + if (m_features & Feat_StatusBar) { + last_time_left = 0; + connect (m, SIGNAL (positioned (int, int)), + this, SLOT (statusPosition (int, int))); + m_view->statusBar ()->insertItem (QString ("--:--"), 1, 0, true); + } +} + +KDE_NO_EXPORT void KMPlayerPart::setLoaded (int percentage) { + PartBase::setLoaded (percentage); + if (percentage < 100) { + m_browserextension->setLoadingProgress (percentage); + m_browserextension->infoMessage + (QString::number (percentage) + i18n ("% Cache fill")); + } +} + +KDE_NO_EXPORT void KMPlayerPart::playingStarted () { + const KMPlayerPartList::iterator e =kmplayerpart_static->partlist.end(); + KMPlayerPartList::iterator i = std::find_if (kmplayerpart_static->partlist.begin (), e, GroupPredicate (this, m_group)); + if (i != e && *i != this && m_view && (*i)->source()) { + m_view->controlPanel ()->setPlaying (true); + m_view->controlPanel ()->showPositionSlider(!!(*i)->source()->length()); + m_view->controlPanel()->enableSeekButtons((*i)->source()->isSeekable()); + emit loading (100); + } else if (m_source) + KMPlayer::PartBase::playingStarted (); + else + return; // ugh + kdDebug () << "KMPlayerPart::processStartedPlaying " << endl; + if (m_settings->sizeratio && !m_noresize && m_source->width() > 0 && m_source->height() > 0) + m_liveconnectextension->setSize (m_source->width(), m_source->height()); + m_browserextension->setLoadingProgress (100); + if (m_started_emited) { + emit completed (); + m_started_emited = false; + } + m_liveconnectextension->started (); + m_browserextension->infoMessage (i18n("KMPlayer: Playing")); +} + +KDE_NO_EXPORT void KMPlayerPart::playingStopped () { + KMPlayer::PartBase::playingStopped (); + if (m_started_emited) { + m_started_emited = false; + m_browserextension->setLoadingProgress (100); + emit completed (); + } + m_liveconnectextension->finished (); + if (m_havehref) + static_cast <KMPlayerHRefSource *>(m_sources["hrefsource"])->finished(); + m_browserextension->infoMessage (i18n ("KMPlayer: Stop Playing")); + if (m_view) + m_view->controlPanel ()->setPlaying (false); +} + +KDE_NO_EXPORT void KMPlayerPart::setMenuZoom (int id) { + int w = 0, h = 0; + if (m_source) + m_source->dimensions (w, h); + if (id == KMPlayer::ControlPanel::menu_zoom100) { + m_liveconnectextension->setSize (w, h); + return; + } + float scale = 1.5; + if (id == KMPlayer::ControlPanel::menu_zoom50) + scale = 0.5; + if (m_view->viewer ()) + m_liveconnectextension->setSize (int (scale * m_view->viewer ()->width ()), + int (scale * m_view->viewer ()->height())); +} + +KDE_NO_EXPORT void KMPlayerPart::statusPosition (int pos, int length) { + int left = (length - pos) / 10; + if (left != last_time_left) { + last_time_left = left; + QString text ("--:--"); + if (left > 0) { + int h = left / 3600; + int m = (left % 3600) / 60; + int s = left % 60; + if (h > 0) + text.sprintf ("%d:%02d:%02d", h, m, s); + else + text.sprintf ("%02d:%02d", m, s); + } + m_view->statusBar ()->changeItem (text, 1); + } +} + +//--------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerBrowserExtension::KMPlayerBrowserExtension (KMPlayerPart * parent) + : KParts::BrowserExtension (parent, "KMPlayer Browser Extension") { +} + +KDE_NO_EXPORT void KMPlayerBrowserExtension::urlChanged (const QString & url) { + emit setLocationBarURL (url); +} + +KDE_NO_EXPORT void KMPlayerBrowserExtension::setLoadingProgress (int percentage) { + emit loadingProgress (percentage); +} + +KDE_NO_EXPORT void KMPlayerBrowserExtension::saveState (QDataStream & stream) { + stream << static_cast <PartBase *> (parent ())->url ().url (); +} + +KDE_NO_EXPORT void KMPlayerBrowserExtension::restoreState (QDataStream & stream) { + QString url; + stream >> url; + static_cast <PartBase *> (parent ())->openURL (KURL(url)); +} + +KDE_NO_EXPORT void KMPlayerBrowserExtension::requestOpenURL (const KURL & url, const QString & target, const QString & service) { + KParts::URLArgs args; + args.frameName = target; + args.serviceType = service; + emit openURLRequest (url, args); +} + +KDE_NO_EXPORT void KMPlayerBrowserExtension::slotRequestOpenURL (const KURL &url, const QString &target) { + requestOpenURL (url, target, QString ()); +} + +//--------------------------------------------------------------------- +/* + * add + * .error.errorCount + * .error.item(count) + * .errorDescription + * .errorCode + * .controls.stop() + * .controls.play() + */ + +enum JSCommand { + notsupported, + canpause, canplay, canstop, canseek, + isfullscreen, isloop, isaspect, showcontrolpanel, + length, width, height, playstate, position, source, setsource, protocol, + gotourl, nextentry, jsc_pause, play, preventry, start, stop, + volume, setvolume, + prop_error, prop_source, prop_volume +}; + +struct KMPLAYER_NO_EXPORT JSCommandEntry { + const char * name; + JSCommand command; + const char * defaultvalue; + const KParts::LiveConnectExtension::Type rettype; +}; + +// keep this list in alphabetic order +// http://service.real.com/help/library/guides/realonescripting/browse/htmfiles/embedmet.htm +static const JSCommandEntry JSCommandList [] = { + { "CanPause", canpause, 0L, KParts::LiveConnectExtension::TypeBool }, + { "CanPlay", canplay, 0L, KParts::LiveConnectExtension::TypeBool }, + { "CanStop", canstop, 0L, KParts::LiveConnectExtension::TypeBool }, + { "DoGotoURL", notsupported, 0L, KParts::LiveConnectExtension::TypeVoid }, + { "DoNextEntry", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "DoPause", jsc_pause, "true", KParts::LiveConnectExtension::TypeBool }, + { "DoPlay", play, 0L, KParts::LiveConnectExtension::TypeBool }, + { "DoPlayPause", play, 0L, KParts::LiveConnectExtension::TypeBool }, + { "DoPrevEntry", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "DoStop", stop, 0L, KParts::LiveConnectExtension::TypeBool }, + { "FileName", prop_source, 0L, KParts::LiveConnectExtension::TypeString }, + { "GetAuthor", notsupported, "noname", KParts::LiveConnectExtension::TypeString }, + { "GetAutoGoToURL", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "GetBackgroundColor", notsupported, "#ffffff", KParts::LiveConnectExtension::TypeString }, + { "GetBandwidthAverage", notsupported, "64", KParts::LiveConnectExtension::TypeNumber }, + { "GetBandwidthCurrent", notsupported, "64", KParts::LiveConnectExtension::TypeNumber }, + { "GetBufferingTimeElapsed", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetBufferingTimeRemaining", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetCanSeek", canseek, 0L, KParts::LiveConnectExtension::TypeBool }, + { "GetCenter", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "GetClipHeight", height, 0L, KParts::LiveConnectExtension::TypeNumber }, + { "GetClipWidth", width, 0L, KParts::LiveConnectExtension::TypeNumber }, + { "GetConnectionBandwidth", notsupported, "64", KParts::LiveConnectExtension::TypeNumber }, + { "GetConsole", notsupported, "unknown", KParts::LiveConnectExtension::TypeString }, + { "GetConsoleEvents", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetControls", notsupported, "buttons", KParts::LiveConnectExtension::TypeString }, + { "GetCopyright", notsupported, "(c) whoever", KParts::LiveConnectExtension::TypeString }, + { "GetCurrentEntry", notsupported, "1", KParts::LiveConnectExtension::TypeNumber }, + { "GetDRMInfo", notsupported, "RNBA", KParts::LiveConnectExtension::TypeString }, + { "GetDoubleSize", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetEntryAbstract", notsupported, "abstract", KParts::LiveConnectExtension::TypeString }, + { "GetEntryAuthor", notsupported, "noname", KParts::LiveConnectExtension::TypeString }, + { "GetEntryCopyright", notsupported, "(c)", KParts::LiveConnectExtension::TypeString }, + { "GetEntryTitle", notsupported, "title", KParts::LiveConnectExtension::TypeString }, + { "GetFullScreen", isfullscreen, 0L, KParts::LiveConnectExtension::TypeBool }, + { "GetImageStatus", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetLastErrorMoreInfoURL", notsupported, "no error", KParts::LiveConnectExtension::TypeString }, + { "GetLastErrorRMACode", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetLastErrorSeverity", notsupported, "6", KParts::LiveConnectExtension::TypeNumber }, + { "GetLastErrorUserCode", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetLastErrorUserString", notsupported, "no error", KParts::LiveConnectExtension::TypeString }, + { "GetLastMessage", notsupported, "no error", KParts::LiveConnectExtension::TypeString }, + { "GetLastStatus", notsupported, "no error", KParts::LiveConnectExtension::TypeString }, + { "GetLength", length, 0L, KParts::LiveConnectExtension::TypeNumber }, + { "GetLiveState", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetLoop", isloop, 0L, KParts::LiveConnectExtension::TypeBool }, + { "GetMaintainAspect", isaspect, 0L, KParts::LiveConnectExtension::TypeBool }, + { "GetMute", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetNumEntries", notsupported, "1", KParts::LiveConnectExtension::TypeNumber }, + { "GetNumLoop", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetNumSources", notsupported, "1", KParts::LiveConnectExtension::TypeNumber }, + { "GetOriginalSize", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "GetPacketsEarly", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetPacketsLate", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetPacketsMissing", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetPacketsOutOfOrder", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetPacketsReceived", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetPacketsTotal", notsupported, "0", KParts::LiveConnectExtension::TypeNumber }, + { "GetPlayState", playstate, 0L, KParts::LiveConnectExtension::TypeNumber }, + { "GetPosition", position, 0L, KParts::LiveConnectExtension::TypeNumber }, + { "GetPreFetch", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetShowAbout", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetShowPreferences", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetShowStatistics", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetShuffle", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetSource", source, 0L, KParts::LiveConnectExtension::TypeString }, + { "GetSourceTransport", protocol, 0L, KParts::LiveConnectExtension::TypeString }, + { "GetStereoState", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "GetTitle", notsupported, "title", KParts::LiveConnectExtension::TypeString }, + { "GetVersionInfo", notsupported, "version", KParts::LiveConnectExtension::TypeString }, + { "GetVolume", volume, "100", KParts::LiveConnectExtension::TypeNumber }, + { "GetWantErrors", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetWantKeyboardEvents", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "GetWantMouseEvents", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "HasNextEntry", notsupported, "false", KParts::LiveConnectExtension::TypeBool }, + { "Pause", jsc_pause, 0L, KParts::LiveConnectExtension::TypeBool }, + { "Play", play, 0L, KParts::LiveConnectExtension::TypeBool }, + { "SetAuthor", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetAutoGoToURL", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetAutoStart", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetBackgroundColor", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetCanSeek", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetCenter", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetConsole", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetConsoleEvents", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetControls", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetCopyright", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetCurrentPosition", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetDoubleSize", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetFileName", setsource, 0L, KParts::LiveConnectExtension::TypeBool }, + { "SetFullScreen", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetImageStatus", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetLoop", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetMaintainAspect", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetMute", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetNumLoop", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetOriginalSize", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetPosition", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetPreFetch", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetShowAbout", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetShowPreferences", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetShowStatistics", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetShuffle", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetSource", setsource, 0L, KParts::LiveConnectExtension::TypeBool }, + { "SetTitle", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetVolume", setvolume, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetWantErrors", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetWantKeyboardEvents", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "SetWantMouseEvents", notsupported, "true", KParts::LiveConnectExtension::TypeBool }, + { "ShowControls", showcontrolpanel, "true", KParts::LiveConnectExtension::TypeBool }, + { "Start", start, 0L, KParts::LiveConnectExtension::TypeBool }, + { "Stop", stop, 0L, KParts::LiveConnectExtension::TypeBool }, + { "Volume", prop_volume, "100", KParts::LiveConnectExtension::TypeNumber }, + { "errorCode", prop_error, "0",KParts::LiveConnectExtension::TypeNumber }, + { "pause", jsc_pause, 0L, KParts::LiveConnectExtension::TypeBool }, + { "play", play, 0L, KParts::LiveConnectExtension::TypeBool }, + { "put", prop_source, 0L, KParts::LiveConnectExtension::TypeString }, + { "stop", stop, 0L, KParts::LiveConnectExtension::TypeBool }, + { "volume", volume, 0L, KParts::LiveConnectExtension::TypeBool }, +}; + +static const JSCommandEntry * getJSCommandEntry (const char * name, int start = 0, int end = sizeof (JSCommandList)/sizeof (JSCommandEntry)) { + if (end - start < 2) { + if (start != end && !strcasecmp (JSCommandList[start].name, name)) + return &JSCommandList[start]; + return 0L; + } + int mid = (start + end) / 2; + int cmp = strcasecmp (JSCommandList[mid].name, name); + if (cmp < 0) + return getJSCommandEntry (name, mid + 1, end); + if (cmp > 0) + return getJSCommandEntry (name, start, mid); + return &JSCommandList[mid]; +} + +KDE_NO_CDTOR_EXPORT KMPlayerLiveConnectExtension::KMPlayerLiveConnectExtension (KMPlayerPart * parent) + : KParts::LiveConnectExtension (parent), player (parent), + lastJSCommandEntry (0L), + m_started (false), + m_enablefinish (false), + m_evaluating (false) { + connect (parent, SIGNAL (started (KIO::Job *)), this, SLOT (started ())); +} + +KDE_NO_CDTOR_EXPORT KMPlayerLiveConnectExtension::~KMPlayerLiveConnectExtension() { + kdDebug () << "KMPlayerLiveConnectExtension::~KMPlayerLiveConnectExtension()" << endl; +} + +KDE_NO_EXPORT void KMPlayerLiveConnectExtension::started () { + m_started = true; +} + +KDE_NO_EXPORT void KMPlayerLiveConnectExtension::finished () { + if (m_started && m_enablefinish) { + KParts::LiveConnectExtension::ArgList args; + args.push_back (qMakePair (KParts::LiveConnectExtension::TypeString, QString("if (window.onFinished) onFinished();"))); + emit partEvent (0, "eval", args); + m_started = true; + m_enablefinish = false; + } +} + +KDE_NO_EXPORT void KMPlayerLiveConnectExtension::evaluate ( + const QString & scr, QString & result) { + QString script (scr); + KParts::LiveConnectExtension::ArgList args; + script = script.replace ('\\', "\\\\"); + script = script.replace ('\n', "\\n"); + script = script.replace ('\r', ""); + script = script.replace ('"', "\\\""); + script = QString ("this.__kmplayer__res=eval(\"%1\")").arg (script); + args.push_back(qMakePair(KParts::LiveConnectExtension::TypeString, script)); + + script_result = "undefined"; + m_evaluating = true; + emit partEvent (0, "eval", args); + m_evaluating = false; + result = script_result; +} + +KDE_NO_EXPORT bool KMPlayerLiveConnectExtension::get + (const unsigned long id, const QString & name, + KParts::LiveConnectExtension::Type & type, + unsigned long & rid, QString & rval) +{ + if (name.startsWith ("__kmplayer__obj_")) { + if (m_evaluating) + return false; + rid = 0; + type = KParts::LiveConnectExtension::TypeString; + rval = "Access denied"; + return true; + } + const char * str = name.ascii (); + kdDebug () << "[01;35mget[00m " << str << endl; + const JSCommandEntry * entry = getJSCommandEntry (str); + if (!entry) + return false; + rid = id; + type = entry->rettype; + switch (entry->command) { + case prop_source: + type = KParts::LiveConnectExtension::TypeString; + rval = player->url ().url (); + break; + case prop_volume: + if (player->view ()) + rval = QString::number (player->process()->viewer ()->view()->controlPanel()->volumeBar()->value()); + break; + case prop_error: + type = KParts::LiveConnectExtension::TypeNumber; + rval = QString::number (0); + break; + default: + lastJSCommandEntry = entry; + type = KParts::LiveConnectExtension::TypeFunction; + } + return true; +} + +KDE_NO_EXPORT bool KMPlayerLiveConnectExtension::put + (const unsigned long, const QString & name, const QString & val) { + if (name == "__kmplayer__res") { + script_result = val; + return true; + } + if (name.startsWith ("__kmplayer__obj_")) + return !m_evaluating; + + kdDebug () << "[01;35mput[00m " << name << "=" << val << endl; + + const JSCommandEntry * entry = getJSCommandEntry (name.ascii ()); + if (!entry) + return false; + switch (entry->command) { + case prop_source: { + KURL url (val); + if (player->allowRedir (url)) + player->openNewURL (url); + break; + } + case prop_volume: + if (player->view ()) + player->process()->viewer ()->view()->controlPanel()->volumeBar()->setValue(val.toInt ()); + break; + default: + return false; + } + return true; +} + +KDE_NO_EXPORT bool KMPlayerLiveConnectExtension::call + (const unsigned long id, const QString & name, + const QStringList & args, KParts::LiveConnectExtension::Type & type, + unsigned long & rid, QString & rval) { + const JSCommandEntry * entry = lastJSCommandEntry; + const char * str = name.ascii (); + if (!entry || strcmp (entry->name, str)) + entry = getJSCommandEntry (str); + if (!entry) + return false; + kdDebug () << "[01;35mentry[00m " << entry->name << endl; + for (unsigned int i = 0; i < args.size (); ++i) + kdDebug () << " " << args[i] << endl; + KMPlayer::View * view = static_cast <KMPlayer::View*> (player->view ()); + if (!view) + return false; + rid = id; + type = entry->rettype; + switch (entry->command) { + case notsupported: + if (entry->rettype != KParts::LiveConnectExtension::TypeVoid) + rval = entry->defaultvalue; + break; + case canpause: + rval = (player->process ()->playing () && !view->controlPanel()->button (KMPlayer::ControlPanel::button_pause)->isOn ()) ? "true" : "false"; + break; + case canplay: + rval = (!player->process ()->playing () || view->controlPanel()->button (KMPlayer::ControlPanel::button_pause)->isOn ()) ? "true" : "false"; + break; + case canstop: + rval = player->process ()->playing () ? "true" : "false"; + break; + case canseek: + rval = player->source ()->isSeekable () ? "true" : "false"; + break; + case play: + if (args.size ()) { + KURL url (args.first ()); + if (player->allowRedir (url)) + player->openNewURL (url); + } else + player->play (); + rval = "true"; + break; + case start: + player->play (); + rval = "true"; + break; + case stop: + player->stop (); + rval = "true"; + break; + case showcontrolpanel: + if (args.size () && + (args.first () == QString::fromLatin1 ("0") || + args.first () == QString::fromLatin1 ("false"))) + static_cast <KMPlayer::View*> (player->view ())->setControlPanelMode (KMPlayer::View::CP_Hide); + else + static_cast <KMPlayer::View*> (player->view ())->setControlPanelMode (KMPlayer::View::CP_Show); + break; + case jsc_pause: + player->pause (); + rval = "true"; + break; + case isloop: + rval = player->settings ()->loop ? "true" : "false"; + break; + case isaspect: + rval = player->settings ()->sizeratio ? "true" : "false"; + break; + case isfullscreen: + rval = static_cast <KMPlayer::View*> (player->view ())->isFullScreen () ? "true" : "false"; + break; + case length: + rval.setNum (player->source ()->length ()); + break; + case width: + rval.setNum (player->source ()->width ()); + break; + case height: + rval.setNum (player->source ()->height ()); + break; + case playstate: // FIXME 0-6 + rval = player->process ()->playing () ? "3" : "0"; + break; + case position: + rval.setNum (player->position ()); + break; + case protocol: + rval = player->url ().protocol (); + break; + case setsource: + rval ="false"; + if (args.size ()) { + KURL url (args.first ()); + if (player->allowRedir (url) && player->openNewURL (url)) + rval = "true"; + } + break; + case setvolume: + if (!args.size ()) + return false; + player->process()->viewer ()->view()->controlPanel()->volumeBar()->setValue(args.first ().toInt ()); + rval = "true"; + break; + case source: + rval = player->url ().url (); + break; + case volume: + if (player->view ()) + rval = QString::number (player->process()->viewer ()->view()->controlPanel()->volumeBar()->value()); + break; + default: + return false; + } + return true; +} + +KDE_NO_EXPORT void KMPlayerLiveConnectExtension::unregister (const unsigned long) { +} + +KDE_NO_EXPORT void KMPlayerLiveConnectExtension::setSize (int w, int h) { + KMPlayer::View * view = static_cast <KMPlayer::View*> (player->view ()); + if (view->controlPanelMode () == KMPlayer::View::CP_Show) + h += view->controlPanel()->height(); + QString jscode; + jscode.sprintf("try { eval(\"this.setAttribute('WIDTH',%d);this.setAttribute('HEIGHT',%d)\"); } catch(e){}", w, h); + KParts::LiveConnectExtension::ArgList args; + args.push_back (qMakePair (KParts::LiveConnectExtension::TypeString, jscode)); + emit partEvent (0, "eval", args); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerHRefSource::KMPlayerHRefSource (PartBase * player) + : Source (i18n ("HREF"), player, "hrefsource") { + //kdDebug () << "KMPlayerHRefSource::KMPlayerHRefSource" << endl; +} + +KDE_NO_CDTOR_EXPORT KMPlayerHRefSource::~KMPlayerHRefSource () { + //kdDebug () << "KMPlayerHRefSource::~KMPlayerHRefSource" << endl; +} + +KDE_NO_EXPORT void KMPlayerHRefSource::init () { + Source::init (); + setIdentified (); +} + +KDE_NO_EXPORT bool KMPlayerHRefSource::hasLength () { + return false; +} + +KDE_NO_EXPORT bool KMPlayerHRefSource::processOutput (const QString & /*str*/) { + //return Source::processOutput (str); + return true; +} + +KDE_NO_EXPORT void KMPlayerHRefSource::setURL (const KURL & url) { + m_url = url; + m_identified = false; + m_finished = false; + Source::setURL (url); + kdDebug () << "KMPlayerHRefSource::setURL " << m_url.url() << endl; +} + +KDE_NO_EXPORT void KMPlayerHRefSource::play () { + kdDebug () << "KMPlayerHRefSource::play " << m_url.url() << endl; + Source * src = m_player->sources () ["urlsource"]; + QString target = src->document ()->document ()-> + getAttribute (StringPool::attr_target); + if (!target.isEmpty ()) { + KMPlayer::Mrl * mrl = src->document ()->mrl (); + static_cast <KMPlayerPart *> (m_player)->browserextension ()->requestOpenURL (mrl->src, target, mrl->mimetype); + } else + m_player->setSource (m_player->sources () ["urlsource"]); +} + +KDE_NO_EXPORT void KMPlayerHRefSource::activate () { + m_player->stop (); + if (m_finished) { + QTimer::singleShot (0, this, SLOT (finished ())); + return; + } + init (); + m_player->setProcess ("mplayer"); + if (m_player->process ()->grabPicture (m_url, 0)) + connect (m_player->process (), SIGNAL (grabReady (const QString &)), + this, SLOT (grabReady (const QString &))); + else { + setURL (KURL ()); + QTimer::singleShot (0, this, SLOT (play ())); + } +} + +KDE_NO_EXPORT void KMPlayerHRefSource::clear () { + setURL (KURL ()); +} + +KDE_NO_EXPORT void KMPlayerHRefSource::grabReady (const QString & path) { + kdDebug () << "KMPlayerHRefSource::grabReady(" << path << ")" << endl; + m_finished = true; + m_grabfile = path; + finished (); +} + +KDE_NO_EXPORT void KMPlayerHRefSource::finished () { + kdDebug () << "KMPlayerHRefSource::finished()" << endl; + KMPlayer::View * view = static_cast <KMPlayer::View*> (m_player->view ()); + if (!view) return; + if (!view->setPicture (m_grabfile)) { + clear (); + QTimer::singleShot (0, this, SLOT (play ())); + return; + } + if (view->viewer ()) + connect (view, SIGNAL (pictureClicked ()), this, SLOT (play ())); +} + +KDE_NO_EXPORT void KMPlayerHRefSource::deactivate () { + kdDebug () << "KMPlayerHRefSource::deactivate()" << endl; + KMPlayer::View * view = static_cast <KMPlayer::View*> (m_player->view ()); + if (!view) return; + view->setPicture (QString ()); + if (view->viewer ()) + disconnect (view, SIGNAL (pictureClicked ()), this, SLOT (play ())); +} + +KDE_NO_EXPORT QString KMPlayerHRefSource::prettyName () { + return i18n ("WEB"); +} + +#include "kmplayer_part.moc" diff --git a/src/kmplayer_part.desktop b/src/kmplayer_part.desktop new file mode 100644 index 0000000..86d597f --- /dev/null +++ b/src/kmplayer_part.desktop @@ -0,0 +1,88 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Embedded MPlayer for KDE +Name[af]=Ingelegde MPlayer vir KDE +Name[ar]=MPlayer مدمج في KDE +Name[be]=Убудаваны MPlayer для KDE +Name[bg]=Вграден MPlayer за KDE +Name[br]=MPlayer enframmet evit KDE +Name[bs]=Ugrađeni MPlayer za KDE +Name[ca]=MPlayer encastat per al KDE +Name[cs]=MPlayer pro KDE +Name[csb]=Wbùdowóny MPlayer dlô KDE +Name[da]=Indlejret MPlayer for KDE +Name[de]=Eingebetteter MPlayer für KDE +Name[el]=Ενσωμάτωση του MPlayer για το KDE +Name[es]=MPlayer embebido para KDE +Name[et]=KDE põimitud MPlayer +Name[fi]=Upotettu MPlayer KDE:lle +Name[fr]=MPlayer intégré pour KDE +Name[gl]=MPlayer Embebido para KDE +Name[he]=נגן MPlayer עבור KDE +Name[hi]=केडीई हेतु एम्बेडेड एमप्लेयर +Name[hu]=Beágyazott MPlayer a KDE-hez +Name[it]=MPlayer integrato per KDE +Name[ja]=KDE のための埋め込み MPlayer +Name[mk]=Вгнезден MPlayer за KDE +Name[nb]=Innebygget MPlayer for KDE +Name[nl]=Ingebedde MPlayer voor KDE +Name[pa]=KDE ਲਈ ਸ਼ਾਮਲ MPlayer +Name[pt]=MPlayer Embebido para o KDE +Name[pt_BR]=MPlayer Integrado ao KDE +Name[ru]=Встроенный MPlayer для KDE +Name[sk]=Vložený MPlayer pre KDE +Name[sr]=Угњеждени MPlayer за KDE +Name[sr@Latn]=Ugnježdeni MPlayer za KDE +Name[sv]=Inbäddad Mplayer för KDE +Name[ta]= KDEவிற்கு விதைத்த ஊடக வாசிப்பான் +Name[th]=โปรแกรมเล่นสื่อ MPlayer แบบฝังตัวสำหรับ KDE +Name[tr]=KDE için gömülmüş MPlayer +Name[uk]=Вбудований MPlayer для KDE +Name[xx]=xxEmbedded MPlayer for KDExx +Name[zh_CN]=KDE 嵌入的 MPlayer +Name[zh_TW]=MPlayer 的 KDE 嵌入式介面 +Comment=Video player plugin (QuickTime, XMovie, Windows Media and RealPlayer compatible) +Comment[af]=Video speler inprop module (Ondersteun QuickTime, XMovie, Windows Media en RealPlayer) +Comment[ar]=قابس القارئ المرئي ( ملائم مع QuickTime, XMovie, Windows Media و RealPlayer) +Comment[be]=Утулка прайгравання відэа (сумяшчальны з QuickTime, XMovie, Windows Media і RealPlayer) +Comment[bg]=Приставка за видео плеър (QuickTime, XMovie, Windows Media и RealPlayer съвместима) +Comment[ca]=Connector per a la reproducció de vídeo (compatible amb QuickTime, XMovie, Windows Media i RealPlayer) +Comment[cs]=Modul video přehrávače (kompatibilní s QuickTime, XMovie, Windows Media a RealPlayer) +Comment[csb]=Pluginsë òdgrëwôcza wideò (zgódne z QickTime, XMovie, Windows Media ë RealPlayer) +Comment[da]=Videoafspiller plugin (QuickTime, XMovie, Windows Media og RealPlayer kompatibel) +Comment[de]=Video player plugin (QuickTime, XMovie, Windows Media und RealPlayer kompatibel) +Comment[el]=Πρόσθετο αναπαραγωγής βίντεο (συμβατό με QuickTime, XMovie, πολυμέσα Windows και RealPlayer) +Comment[es]=Complemento de reproducción de vídeo (compatible con QuickTime, XMovie, Windows Media y RealPlayer) +Comment[et]=Videomängija plugin (QuickTime, XMovie, Windows Media ja RealPlayer) +Comment[fr]=Module de lecture de vidéos (compatible QuickTime, XMovie, Windows Media et RealPlayer) +Comment[gl]=Plugin de reproduzón de vídeo (compatível con QuickTime, XMovie, Windows Media e RealPlayer) +Comment[he]=תוסף וידאו לניגון (QuickTime, XMovie, מדיה של חלונות ותואם RealPlayer) +Comment[hi]=वीडियो प्लेयर प्लगइन (क्विक-टाइम, एक्समूवी, विंडोज़ मीडिया तथा रीयल-प्लेयर कंपेटिबल) +Comment[it]=Plugin lettore video (compatibile con QuickTime, XMovie, Windows Media e RealPlayer) +Comment[ja]=ビデオプレーヤプラグイン (QuickTime, XMovie, Windows Media, RealPlayer をサポート) +Comment[ka]=ვიდეოდამკვრელის მოდული (QuickTime, XMovie, Windows Media და RealPlayer თავსებადი) +Comment[mk]=Приклучок за видеоизведувач (компатибилен со QuickTime, XMovie, Windows Media и RealPlayer) +Comment[nb]=Tilleggsmodul for videospiller (kompatibel med QuickTime, XMovie, Windows Media og RealPlayer) +Comment[nl]=Videospelerplugin (ondersteuning voor Quicktime, XMovie, Windows Media- en RealAudio-speler) +Comment[pa]=ਵੀਡਿਆ ਪਲੇਅਰ ਪਲੱਗਿੰਨ (QuickTime, XMovie, Windows Media ਅਤੇ RealPlayer ਅਨੁਕੂਲ) +Comment[pt]='Plugin' de reprodução de vídeo (compatível com QuickTime, XMovie, Windows Media e RealPlayer) +Comment[pt_BR]=Plugin de reprodução de vídeo (compatível com QuickTime, XMovie, Windows Media e RealPlayer) +Comment[ru]=Модуль видеоплеера (совместимый с QuickTime, XMovie, Windows Media и RealPlayer) +Comment[sk]=Plugin prehrávača videa (kompatibilný s QuickTime, XMovie, Windows Media a RealPlayer) +Comment[sr]=Прикључак за пуштање видеа (компатибилан са: QuickTime, XMovie, Windows Media, RealPlayer) +Comment[sr@Latn]=Priključak za puštanje videa (kompatibilan sa: QuickTime, XMovie, Windows Media, RealPlayer) +Comment[sv]=Insticksprogram för videospelare (fungerar med Quicktime, Xmovie, Windows Media och Realplayer) +Comment[ta]=வீடியோ சொருகி(விரைவுநேரம், Xபடம், Windows படம் மற்றும் RealPlayer compatible) +Comment[th]=ปลั๊กอินโปรแกรมเล่นวิดีโอ (ใช้ด้วยกันได้กับ QuickTime, XMovie, Windows Media และ RealPlayer) +Comment[tr]=Video oynatıcı eklentisi (QuickTime, XMovie, Windows Media ve RealPlayer ile uyumlu) +Comment[uk]=Втулок відео-програвача (програє QuickTime, XMovie, Windows Media і RealPlayer) +Comment[xx]=xxVideo player plugin (QuickTime, XMovie, Windows Media and RealPlayer compatible)xx +Comment[zh_TW]=視像播放程式 (可播放 QuickTime, XMovie, Windows Media 和 RealPlayer) +X-KDE-Library=libkmplayerpart +# Keep in sync with the audio types in kmplayer.desktop +MimeType=application/ogg;application/smil;application/vnd.ms-asf;application/vnd.rn-realmedia;application/x-kmplayer;application/x-mplayer2;application/x-ogg;application/xspf+xml;video/avi;video/mediaplayer;video/mp4;video/mpeg;video/quicktime;video/vnd.rn-realvideo;video/x-avi;video/x-flic;video/x-matroska;video/x-ms-asf;video/x-msvideo;video/x-ms-wmp;video/x-ms-wmv;video/x-ms-wvx;video/x-ogm;video/x-theora;uri/mms;uri/pnm;uri/rtspt;uri/rtspu; +Type=Service +Icon=kmplayer +ServiceTypes=KParts/ReadOnlyPart,Browser/View,KMediaPlayer/Player +X-KDE-BrowserView-PluginsInfo=kmplayer/pluginsinfo +InitialPreference=5 diff --git a/src/kmplayer_part.h b/src/kmplayer_part.h new file mode 100644 index 0000000..e60d983 --- /dev/null +++ b/src/kmplayer_part.h @@ -0,0 +1,176 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef KMPLAYER_PART_H +#define KMPLAYER_PART_H + +#include <kparts/browserextension.h> +#include "kmplayerpartbase.h" +#include "kmplayersource.h" + + +class KAboutData; +class KMPlayerPart; +class KInstance; +class JSCommandEntry; + +/* + * Wrapper source for URLSource that has a HREF attribute + */ +class KMPLAYER_NO_EXPORT KMPlayerHRefSource : public KMPlayer::Source { + Q_OBJECT +public: + KMPlayerHRefSource (KMPlayer::PartBase * player); + virtual ~KMPlayerHRefSource (); + virtual bool processOutput (const QString & line); + virtual bool hasLength (); + + void setURL (const KURL &); + void clear (); + virtual QString prettyName (); +public slots: + virtual void init (); + virtual void activate (); + virtual void deactivate (); + void finished (); +private slots: + void grabReady (const QString & path); + void play (); +private: + QString m_grabfile; + bool m_finished; +}; + + +/* + * Part notifications to hosting application + */ +class KMPLAYER_NO_EXPORT KMPlayerBrowserExtension : public KParts::BrowserExtension { + Q_OBJECT +public: + KMPlayerBrowserExtension(KMPlayerPart *parent); + KDE_NO_CDTOR_EXPORT ~KMPlayerBrowserExtension () {} + void urlChanged (const QString & url); + void setLoadingProgress (int percentage); + + void saveState (QDataStream & stream); + void restoreState (QDataStream & stream); + void requestOpenURL (const KURL & url, const QString & target, const QString & service); +public slots: + void slotRequestOpenURL (const KURL & url, const QString & target); +}; + +/* + * Part javascript support + */ +class KMPLAYER_NO_EXPORT KMPlayerLiveConnectExtension : public KParts::LiveConnectExtension { + Q_OBJECT +public: + KMPlayerLiveConnectExtension (KMPlayerPart * parent); + ~KMPlayerLiveConnectExtension (); + + // LiveConnect interface + bool get (const unsigned long, const QString &, + KParts::LiveConnectExtension::Type &, unsigned long &, QString &); + bool put (const unsigned long, const QString &, const QString &); + bool call (const unsigned long, const QString &, + const QStringList &, KParts::LiveConnectExtension::Type &, + unsigned long &, QString &); + void unregister (const unsigned long); + void sendEvent(const unsigned long objid, const QString & event, const KParts::LiveConnectExtension::ArgList & args ) { + emit partEvent(objid, event, args); + } + + void enableFinishEvent (bool b = true) { m_enablefinish = b; } +signals: + void partEvent (const unsigned long, const QString &, + const KParts::LiveConnectExtension::ArgList &); +public slots: + void setSize (int w, int h); + void started (); + void finished (); + void evaluate (const QString & script, QString & result); +private: + KMPlayerPart * player; + QString script_result; + const JSCommandEntry * lastJSCommandEntry; + bool m_started; + bool m_enablefinish; + bool m_evaluating; +}; + + +/* + * Part that gets created when used a KPart + */ +class KMPLAYER_NO_EXPORT KMPlayerPart : public KMPlayer::PartBase { + Q_OBJECT + friend struct GroupPredicate; +public: + enum Features { + Feat_Unknown = 0, + Feat_Viewer = 0x01, Feat_Controls = 0x02, + Feat_Label = 0x04, Feat_StatusBar = 0x08, + Feat_InfoPanel = 0x10, Feat_VolumeSlider = 0x20, Feat_PlayList = 0x40, + Feat_ImageWindow = 0x80, Feat_All = 0xff + }; + KMPlayerPart (QWidget * wparent, const char * wname, + QObject * parent, const char * name, const QStringList &args); + ~KMPlayerPart (); + + KDE_NO_EXPORT KMPlayerBrowserExtension * browserextension() const + { return m_browserextension; } + KMPlayerLiveConnectExtension * liveconnectextension () const + { return m_liveconnectextension; } + KDE_NO_EXPORT bool hasFeature (int f) { return m_features & f; } + bool allowRedir (const KURL & url) const; + void connectToPart (KMPlayerPart *); + KMPlayerPart * master () const { return m_master; } + void setMaster (KMPlayerPart * m) { m_master = m; } + virtual void setLoaded (int percentage); + bool openNewURL (const KURL & url); // for JS interface +public slots: + virtual bool openURL (const KURL & url); + virtual bool closeURL (); + void setMenuZoom (int id); +protected slots: + virtual void playingStarted (); + virtual void playingStopped (); + void viewerPartDestroyed (QObject *); + void viewerPartProcessChanged (const char *); + void viewerPartSourceChanged (KMPlayer::Source *, KMPlayer::Source *); + void waitForImageWindowTimeOut (); + void statusPosition (int pos, int length); +private: + void setAutoControls (bool); + KMPlayerPart * m_master; + KMPlayerBrowserExtension * m_browserextension; + KMPlayerLiveConnectExtension * m_liveconnectextension; + QString m_group; + KURL m_docbase; + QString m_src_url; + QString m_file_name; + int m_features; + int last_time_left; + bool m_started_emited : 1; + //bool m_noresize : 1; + bool m_havehref : 1; +}; + + +#endif diff --git a/src/kmplayer_rp.cpp b/src/kmplayer_rp.cpp new file mode 100644 index 0000000..c255e39 --- /dev/null +++ b/src/kmplayer_rp.cpp @@ -0,0 +1,497 @@ +/** + * Copyright (C) 2006 by Koos Vriezen <[email protected]> + * + * 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 <config.h> + +#include <qcolor.h> +#include <qimage.h> +#include <qtimer.h> + +#include <kdebug.h> + +#include "kmplayer_rp.h" +#include "kmplayer_smil.h" + +using namespace KMPlayer; + + +KDE_NO_CDTOR_EXPORT RP::Imfl::Imfl (NodePtr & d) + : Mrl (d, id_node_imfl), + fit (fit_hidden), + duration (0), + needs_scene_img (0) {} + +KDE_NO_CDTOR_EXPORT RP::Imfl::~Imfl () { +} + +KDE_NO_EXPORT void RP::Imfl::closed () { + for (NodePtr n = firstChild (); n; n = n->nextSibling ()) + if (RP::id_node_head == n->id) { + AttributePtr a = convertNode <Element> (n)->attributes ()->first (); + for (; a; a = a->nextSibling ()) { + if (StringPool::attr_width == a->name ()) { + width = a->value ().toInt (); + } else if (StringPool::attr_height == a->name ()) { + height = a->value ().toInt (); + } else if (a->name () == "duration") { + int dur; + parseTime (a->value ().lower (), dur); + duration = dur; + } + } + } +} + +KDE_NO_EXPORT void RP::Imfl::defer () { + kdDebug () << "RP::Imfl::defer " << endl; + setState (state_deferred); + for (Node * n = firstChild ().ptr (); n; n = n->nextSibling ().ptr ()) + if (n->id == RP::id_node_image && !n->active ()) + n->activate (); +} + +KDE_NO_EXPORT void RP::Imfl::activate () { + kdDebug () << "RP::Imfl::activate " << endl; + resolved = true; + setState (state_activated); + int timings_count = 0; + for (NodePtr n = firstChild (); n; n = n->nextSibling ()) + switch (n->id) { + 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: + case RP::id_node_viewchange: + n->activate (); // set their start timers + timings_count++; + break; + case RP::id_node_image: + if (!n->active ()) + n->activate (); + break; + } + if (duration > 0) + duration_timer = document ()->setTimeout (this, duration * 100); + else if (!timings_count) + finish (); +} + +KDE_NO_EXPORT void RP::Imfl::finish () { + kdDebug () << "RP::Imfl::finish " << endl; + Mrl::finish (); + if (duration_timer) { + document ()->cancelTimer (duration_timer); + duration_timer = 0; + } + for (NodePtr n = firstChild (); n; n = n->nextSibling ()) + if (n->unfinished ()) + n->finish (); +} + +KDE_NO_EXPORT void RP::Imfl::childDone (NodePtr) { + if (unfinished () && !duration_timer) { + for (NodePtr n = firstChild (); n; n = n->nextSibling ()) + switch (n->id) { + case RP::id_node_crossfade: + case RP::id_node_fadein: + case RP::id_node_fadeout: + case RP::id_node_fill: + if (n->unfinished ()) + return; + } + finish (); + } +} + +KDE_NO_EXPORT void RP::Imfl::deactivate () { + kdDebug () << "RP::Imfl::deactivate " << endl; + if (unfinished ()) + finish (); + if (!active ()) + return; // calling finish might call deactivate() as well + setState (state_deactivated); + for (NodePtr n = firstChild (); n; n = n->nextSibling ()) + if (n->active ()) + n->deactivate (); + rp_surface = Mrl::getSurface (0L); +} + +KDE_NO_EXPORT bool RP::Imfl::handleEvent (EventPtr event) { + if (event->id () == event_timer) { + TimerEvent * te = static_cast <TimerEvent *> (event.ptr ()); + if (te->timer_info == duration_timer) { + kdDebug () << "RP::Imfl timer " << duration << endl; + duration_timer = 0; + if (unfinished ()) + finish (); + } + } + return true; +} + +KDE_NO_EXPORT void RP::Imfl::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT Surface *RP::Imfl::surface () { + if (!rp_surface) { + rp_surface = Mrl::getSurface (this); + if (rp_surface) { + if (width <= 0 || width > 32000) + width = rp_surface->bounds.width (); + if (height <= 0 || height > 32000) + height = rp_surface->bounds.height (); + } + } + return rp_surface.ptr (); +} + +KDE_NO_EXPORT NodePtr RP::Imfl::childFromTag (const QString & tag) { + const char * ctag = tag.latin1 (); + if (!strcmp (ctag, "head")) + return new DarkNode (m_doc, "head", RP::id_node_head); + else if (!strcmp (ctag, "image")) + return new RP::Image (m_doc); + else if (!strcmp (ctag, "fill")) + return new RP::Fill (m_doc); + else if (!strcmp (ctag, "wipe")) + return new RP::Wipe (m_doc); + else if (!strcmp (ctag, "viewchange")) + return new RP::ViewChange (m_doc); + else if (!strcmp (ctag, "crossfade")) + return new RP::Crossfade (m_doc); + else if (!strcmp (ctag, "fadein")) + return new RP::Fadein (m_doc); + else if (!strcmp (ctag, "fadeout")) + return new RP::Fadeout (m_doc); + return 0L; +} + +KDE_NO_EXPORT void RP::Imfl::repaint () { + if (!active ()) + kdWarning () << "Spurious Imfl repaint" << endl; + else if (surface () && width > 0 && height > 0) + rp_surface->repaint (SRect (0, 0, width, height)); +} + +KDE_NO_CDTOR_EXPORT RP::Image::Image (NodePtr & doc) + : Mrl (doc, id_node_image) +{} + +KDE_NO_CDTOR_EXPORT RP::Image::~Image () { +} + +KDE_NO_EXPORT void RP::Image::closed () { + src = getAttribute (StringPool::attr_name); +} + +KDE_NO_EXPORT void RP::Image::activate () { + kdDebug () << "RP::Image::activate" << endl; + setState (state_activated); + isPlayable (); // update src attribute + cached_img.setUrl (absolutePath ()); + if (cached_img.isEmpty ()) { + wget (absolutePath ()); + } else { + width = cached_img.data->image->width (); + height = cached_img.data->image->height (); + } +} + +KDE_NO_EXPORT void RP::Image::begin () { + Node::begin (); +} + +KDE_NO_EXPORT void RP::Image::deactivate () { + cached_img.setUrl (QString ()); + if (img_surface) { + img_surface->remove (); + img_surface = NULL; + } + setState (state_deactivated); + postpone_lock = 0L; +} + + +KDE_NO_EXPORT void RP::Image::remoteReady (QByteArray & data) { + kdDebug () << "RP::Image::remoteReady" << endl; + if (!data.isEmpty () && cached_img.isEmpty ()) { + QImage * img = new QImage (data); + if (!img->isNull ()) { + cached_img.data->image = img; + width = img->width (); + height = img->height (); + } else { + delete img; + } + } + postpone_lock = 0L; +} + +KDE_NO_EXPORT bool RP::Image::isReady (bool postpone_if_not) { + if (downloading () && postpone_if_not) + postpone_lock = document ()->postpone (); + return !downloading (); +} + +KDE_NO_EXPORT Surface *RP::Image::surface () { + if (!img_surface && !cached_img.isEmpty ()) { + Node * p = parentNode ().ptr (); + if (p && p->id == RP::id_node_imfl) { + Surface *ps = static_cast <RP::Imfl *> (p)->surface (); + if (ps) + img_surface = ps->createSurface (this, + SRect (0, 0, width, height)); + } + } + return img_surface; +} + +KDE_NO_CDTOR_EXPORT RP::TimingsBase::TimingsBase (NodePtr & d, const short i) + : Element (d, i), x (0), y (0), w (0), h (0), start (0), duration (0) {} + +KDE_NO_EXPORT void RP::TimingsBase::activate () { + setState (state_activated); + x = y = w = h = 0; + srcx = srcy = srcw = srch = 0; + for (Attribute * a= attributes ()->first ().ptr (); a; a = a->nextSibling ().ptr ()) { + if (a->name () == StringPool::attr_target) { + for (NodePtr n = parentNode()->firstChild(); n; n= n->nextSibling()) + if (convertNode <Element> (n)-> + getAttribute ("handle") == a->value ()) + target = n; + } else if (a->name () == "start") { + int dur; + parseTime (a->value ().lower (), dur); + start = dur; + } else if (a->name () == "duration") { + int dur; + parseTime (a->value ().lower (), dur); + duration = dur; + } else if (a->name () == "dstx") { + x = a->value ().toInt (); + } else if (a->name () == "dsty") { + y = a->value ().toInt (); + } else if (a->name () == "dstw") { + w = a->value ().toInt (); + } else if (a->name () == "dsth") { + h = a->value ().toInt (); + } else if (a->name () == "srcx") { + srcx = a->value ().toInt (); + } else if (a->name () == "srcy") { + srcy = a->value ().toInt (); + } else if (a->name () == "srcw") { + srcw = a->value ().toInt (); + } else if (a->name () == "srch") { + srch = a->value ().toInt (); + } + } + start_timer = document ()->setTimeout (this, start *100); +} + +KDE_NO_EXPORT void RP::TimingsBase::deactivate () { + if (unfinished ()) + finish (); + setState (state_deactivated); +} + +KDE_NO_EXPORT bool RP::TimingsBase::handleEvent (EventPtr event) { + if (event->id () == event_timer) { + TimerEvent * te = static_cast <TimerEvent *> (event.ptr ()); + if (te->timer_info == update_timer && duration > 0) { + update (100 * ++curr_step / duration); + te->interval = true; + } else if (te->timer_info == start_timer) { + start_timer = 0; + duration_timer = document ()->setTimeout (this, duration * 100); + begin (); + } else if (te->timer_info == duration_timer) { + duration_timer = 0; + update (100); + finish (); + } else + return false; + return true; + } else if (event->id () == event_postponed) { + if (!static_cast <PostponedEvent *> (event.ptr ())->is_postponed) { + document_postponed = 0L; // disconnect + update (duration > 0 ? 0 : 100); + } + } + return false; +} + +KDE_NO_EXPORT void RP::TimingsBase::begin () { + progress = 0; + setState (state_began); + if (target) + target->begin (); + if (duration > 0) { + steps = duration; // 10/s updates + update_timer = document ()->setTimeout (this, 100); // 50ms + curr_step = 1; + } +} + +KDE_NO_EXPORT void RP::TimingsBase::update (int percentage) { + progress = percentage; + Node * p = parentNode ().ptr (); + if (p->id == RP::id_node_imfl) + static_cast <RP::Imfl *> (p)->repaint (); +} + +KDE_NO_EXPORT void RP::TimingsBase::finish () { + progress = 100; + if (start_timer) { + document ()->cancelTimer (start_timer); + start_timer = 0; + } else if (duration_timer) { + document ()->cancelTimer (duration_timer); + duration_timer = 0; + } + if (update_timer) { + document ()->cancelTimer (update_timer); + update_timer = 0; + } + document_postponed = 0L; // disconnect + Element::finish (); +} + +KDE_NO_EXPORT void RP::Crossfade::activate () { + TimingsBase::activate (); +} + +KDE_NO_EXPORT void RP::Crossfade::begin () { + //kdDebug () << "RP::Crossfade::begin" << endl; + TimingsBase::begin (); + if (target && target->id == id_node_image) { + RP::Image * img = static_cast <RP::Image *> (target.ptr ()); + if (!img->isReady (true)) + document_postponed = document()->connectTo (this, event_postponed); + else + update (duration > 0 ? 0 : 100); + } +} + +KDE_NO_EXPORT void RP::Crossfade::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT void RP::Fadein::activate () { + // pickup color from Fill that should be declared before this node + from_color = 0; + TimingsBase::activate (); +} + +KDE_NO_EXPORT void RP::Fadein::begin () { + //kdDebug () << "RP::Fadein::begin" << endl; + TimingsBase::begin (); + if (target && target->id == id_node_image) { + RP::Image * img = static_cast <RP::Image *> (target.ptr ()); + if (!img->isReady (true)) + document_postponed = document()->connectTo (this, event_postponed); + else + update (duration > 0 ? 0 : 100); + } +} + +KDE_NO_EXPORT void RP::Fadein::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT void RP::Fadeout::activate () { + to_color = QColor (getAttribute ("color")).rgb (); + TimingsBase::activate (); +} + +KDE_NO_EXPORT void RP::Fadeout::begin () { + //kdDebug () << "RP::Fadeout::begin" << endl; + TimingsBase::begin (); +} + +KDE_NO_EXPORT void RP::Fadeout::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT void RP::Fill::activate () { + color = QColor (getAttribute ("color")).rgb (); + TimingsBase::activate (); +} + +KDE_NO_EXPORT void RP::Fill::begin () { + setState (state_began); + update (0); +} + +KDE_NO_EXPORT void RP::Fill::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT void RP::Wipe::activate () { + //TODO implement 'type="push"' + QString dir = getAttribute ("direction").lower (); + direction = dir_right; + if (dir == QString::fromLatin1 ("left")) + direction = dir_left; + else if (dir == QString::fromLatin1 ("up")) + direction = dir_up; + else if (dir == QString::fromLatin1 ("down")) + direction = dir_down; + TimingsBase::activate (); +} + +KDE_NO_EXPORT void RP::Wipe::begin () { + //kdDebug () << "RP::Wipe::begin" << endl; + TimingsBase::begin (); + if (target && target->id == id_node_image) { + RP::Image * img = static_cast <RP::Image *> (target.ptr ()); + if (!img->isReady (true)) + document_postponed = document()->connectTo (this, event_postponed); + else + update (duration > 0 ? 0 : 100); + } +} + +KDE_NO_EXPORT void RP::Wipe::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT void RP::ViewChange::activate () { + TimingsBase::activate (); +} + +KDE_NO_EXPORT void RP::ViewChange::begin () { + kdDebug () << "RP::ViewChange::begin" << endl; + setState (state_began); + Node * p = parentNode ().ptr (); + if (p->id == RP::id_node_imfl) + static_cast <RP::Imfl *> (p)->needs_scene_img++; + update (0); +} + +KDE_NO_EXPORT void RP::ViewChange::finish () { + Node * p = parentNode ().ptr (); + if (p && p->id == RP::id_node_imfl) + static_cast <RP::Imfl *> (p)->needs_scene_img--; + TimingsBase::finish (); +} + +KDE_NO_EXPORT void RP::ViewChange::accept (Visitor * v) { + v->visit (this); +} diff --git a/src/kmplayer_rp.h b/src/kmplayer_rp.h new file mode 100644 index 0000000..5c43a0f --- /dev/null +++ b/src/kmplayer_rp.h @@ -0,0 +1,193 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2006-2007 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYER_RP_H_ +#define _KMPLAYER_RP_H_ + +#include <qobject.h> +#include <qstring.h> + +#include "kmplayerplaylist.h" +#include "kmplayer_smil.h" + +namespace KIO { + class Job; +} + +namespace KMPlayer { + +/** + * RealPix support classes + */ +namespace RP { + +const short id_node_imfl = 150; +const short id_node_head = 151; +const short id_node_image = 152; +const short id_node_crossfade = 153; +const short id_node_fill = 154; +const short id_node_wipe = 155; +const short id_node_fadein = 156; +const short id_node_fadeout = 157; +const short id_node_viewchange = 158; +const short id_node_animate = 159; + +class KMPLAYER_NO_EXPORT Imfl : public Mrl { +public: + Imfl (NodePtr & d); + ~Imfl (); + KDE_NO_EXPORT virtual const char * nodeName () const { return "imfl"; } + virtual NodePtr childFromTag (const QString & tag); + virtual void closed (); + virtual void defer (); // start loading the images if not yet done + virtual void activate (); // start timings, handle paint events + virtual void finish (); // end the timings + virtual void deactivate (); // stop handling paint events + virtual void childDone (NodePtr child); // for if no duration_timer set + KDE_NO_EXPORT virtual bool expose () const { return false; } + KDE_NO_EXPORT virtual PlayType playType () const { return play_type_image; } + virtual bool handleEvent (EventPtr event); + virtual void accept (Visitor *); + Surface *surface (); + void repaint (); // called whenever something changes on image + Fit fit; // how to layout images + unsigned int duration; // cached attributes of head + TimerInfoPtrW duration_timer; + SurfacePtrW rp_surface; + int needs_scene_img; +}; + +class KMPLAYER_NO_EXPORT TimingsBase : public Element { +public: + TimingsBase (NodePtr & d, const short id); + KDE_NO_CDTOR_EXPORT ~TimingsBase () {} + virtual void activate (); // start the 'start_timer' + virtual void begin (); // start_timer has expired + virtual void finish (); // ?duration_timer has expired? + virtual void deactivate (); // disabled + virtual bool handleEvent (EventPtr event); + KDE_NO_EXPORT virtual bool expose () const { return false; } + int progress; + Single x, y, w, h; + Single srcx, srcy, srcw, srch; + NodePtrW target; +protected: + void update (int percentage); + unsigned int start, duration; + int steps, curr_step; + TimerInfoPtrW start_timer; + TimerInfoPtrW duration_timer; + TimerInfoPtrW update_timer; + ConnectionPtr document_postponed; +}; + +class KMPLAYER_NO_EXPORT Crossfade : public TimingsBase { +public: + KDE_NO_CDTOR_EXPORT Crossfade (NodePtr & d) + : TimingsBase (d, id_node_crossfade) {} + KDE_NO_CDTOR_EXPORT ~Crossfade () {} + KDE_NO_EXPORT virtual const char * nodeName () const { return "crossfade"; } + virtual void activate (); + virtual void begin (); + virtual void accept (Visitor *); +}; + +class KMPLAYER_NO_EXPORT Fadein : public TimingsBase { +public: + KDE_NO_CDTOR_EXPORT Fadein (NodePtr & d) : TimingsBase(d, id_node_fadein) {} + KDE_NO_CDTOR_EXPORT ~Fadein () {} + KDE_NO_EXPORT virtual const char * nodeName () const { return "fadein"; } + virtual void activate (); + virtual void begin (); + virtual void accept (Visitor *); + unsigned int from_color; +}; + +class KMPLAYER_NO_EXPORT Fadeout : public TimingsBase { +public: + KDE_NO_CDTOR_EXPORT Fadeout(NodePtr &d) : TimingsBase(d, id_node_fadeout) {} + KDE_NO_CDTOR_EXPORT ~Fadeout () {} + KDE_NO_EXPORT virtual const char * nodeName () const { return "fadeout"; } + virtual void activate (); + virtual void begin (); + virtual void accept (Visitor *); + unsigned int to_color; +}; + +class KMPLAYER_NO_EXPORT Fill : public TimingsBase { +public: + KDE_NO_CDTOR_EXPORT Fill (NodePtr & d) : TimingsBase (d, id_node_fill) {} + KDE_NO_CDTOR_EXPORT ~Fill () {} + KDE_NO_EXPORT virtual const char * nodeName () const { return "fill"; } + virtual void activate (); + virtual void begin (); + unsigned int fillColor () const { return color; } + virtual void accept (Visitor *); + unsigned int color; +}; + +class KMPLAYER_NO_EXPORT Wipe : public TimingsBase { +public: + KDE_NO_CDTOR_EXPORT Wipe (NodePtr & d) : TimingsBase (d, id_node_wipe) {} + KDE_NO_CDTOR_EXPORT ~Wipe () {} + KDE_NO_EXPORT virtual const char * nodeName () const { return "wipe"; } + virtual void activate (); + virtual void begin (); + virtual void accept (Visitor *); + enum { dir_right, dir_left, dir_up, dir_down } direction; +}; + +class KMPLAYER_NO_EXPORT ViewChange : public TimingsBase { +public: + KDE_NO_CDTOR_EXPORT ViewChange (NodePtr & d) + : TimingsBase (d, id_node_viewchange) {} + KDE_NO_CDTOR_EXPORT ~ViewChange () {} + KDE_NO_EXPORT virtual const char * nodeName() const { return "viewchange"; } + virtual void activate (); + virtual void begin (); + virtual void finish (); + virtual void accept (Visitor *); +}; + +class KMPLAYER_NO_EXPORT Image : public RemoteObject, public Mrl { + PostponePtr postpone_lock; +public: + Image (NodePtr & d); + ~Image (); + KDE_NO_EXPORT virtual const char * nodeName () const { return "image"; } + virtual void activate (); + virtual void begin (); + virtual void deactivate (); + virtual void closed (); + bool isReady (bool postpone_if_not = false); // is downloading ready + Surface *surface (); + SurfacePtrW img_surface; + CachedImage cached_img; + bool expose () const { return false; } +protected: + virtual void remoteReady (QByteArray & data); +}; + +} // RP namespace + +} // KMPlayer namespace + +#endif //_KMPLAYER_RP_H_ + diff --git a/src/kmplayer_rss.cpp b/src/kmplayer_rss.cpp new file mode 100644 index 0000000..133b4e8 --- /dev/null +++ b/src/kmplayer_rss.cpp @@ -0,0 +1,130 @@ +/** + * Copyright (C) 2005 by Koos Vriezen <[email protected]> + * + * 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 <config.h> +#include <kdebug.h> +#include "kmplayer_rss.h" + +using namespace KMPlayer; + +KDE_NO_EXPORT NodePtr RSS::Rss::childFromTag (const QString & tag) { + if (!strcmp (tag.latin1 (), "channel")) + return new RSS::Channel (m_doc); + return 0L; +} + +KDE_NO_EXPORT NodePtr RSS::Channel::childFromTag (const QString & tag) { + const char *ctag = tag.ascii (); + if (!strcmp (ctag, "item")) + return new RSS::Item (m_doc); + else if (!strcmp (ctag, "title")) + return new DarkNode (m_doc, tag, id_node_title); + return 0L; +} + +KDE_NO_EXPORT void RSS::Channel::closed () { + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->id == id_node_title) { + pretty_name = c->innerText ().simplifyWhiteSpace (); + break; + } +} + +KDE_NO_EXPORT bool RSS::Channel::expose () const { + return !pretty_name.isEmpty () || //return false if no title and only one + previousSibling () || nextSibling (); +} + +KDE_NO_EXPORT NodePtr RSS::Item::childFromTag (const QString & tag) { + const char *ctag = tag.ascii (); + if (!strcmp (ctag, "enclosure")) + return new RSS::Enclosure (m_doc); + else if (!strcmp (ctag, "title")) + return new DarkNode (m_doc, tag, id_node_title); + else if (!strcmp (ctag, "description")) + return new DarkNode (m_doc, tag, id_node_description); + return 0L; +} + +KDE_NO_EXPORT void RSS::Item::closed () { + cached_play_type = play_type_none; + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) { + switch (c->id) { + case id_node_title: + pretty_name = c->innerText ().simplifyWhiteSpace (); + break; + case id_node_enclosure: + enclosure = c; + src = c->mrl ()->src; + break; + case id_node_description: + cached_play_type = play_type_info; + break; + } + } + if (enclosure && !enclosure->mrl ()->src.isEmpty ()) + cached_play_type = play_type_audio; +} + +KDE_NO_EXPORT Mrl * RSS::Item::linkNode () { + if (enclosure) + return enclosure->mrl (); + return Mrl::linkNode (); +} + +KDE_NO_EXPORT void RSS::Item::activate () { + PlayListNotify * n = document()->notify_listener; + if (n) { + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->id == id_node_description) { + QString s = c->innerText (); + n->setInfoMessage (s); + if (!enclosure && !s.isEmpty ()) { + setState (state_activated); + begin (); + timer = document ()->setTimeout (this, 5000+s.length()*200); + return; + } + break; + } + } + Mrl::activate (); +} + +KDE_NO_EXPORT void RSS::Item::deactivate () { + if (timer) { + document ()->cancelTimer (timer); + timer = 0L; + } + PlayListNotify * n = document()->notify_listener; + if (n) + n->setInfoMessage (QString ()); + Mrl::deactivate (); +} + +KDE_NO_EXPORT bool RSS::Item::handleEvent (EventPtr event) { + if (event->id () == event_timer) { + timer = 0L; + finish (); + } + return true; +} + +KDE_NO_EXPORT void RSS::Enclosure::closed () { + src = getAttribute (StringPool::attr_url); +} diff --git a/src/kmplayer_rss.h b/src/kmplayer_rss.h new file mode 100644 index 0000000..229610d --- /dev/null +++ b/src/kmplayer_rss.h @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2005-2006 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYER_RSS_H_ +#define _KMPLAYER_RSS_H_ + +#include <qstring.h> + +#include "kmplayerplaylist.h" + +namespace KMPlayer { + +namespace RSS { + +const short id_node_rss = 200; +const short id_node_channel = 201; +const short id_node_item = 202; +const short id_node_title = 203; +const short id_node_description = 204; +const short id_node_enclosure = 205; + +/** + * '<RSS>' tag + */ +class KMPLAYER_NO_EXPORT Rss : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Rss (NodePtr & d) : Mrl (d, id_node_rss) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "rss"; } + bool expose () const { return false; } +}; + +class KMPLAYER_NO_EXPORT Channel : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Channel (NodePtr & d) : Mrl (d, id_node_channel) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "channel"; } + PlayType playType () { return play_type_none; } + void closed (); + bool expose () const; +}; + +class KMPLAYER_NO_EXPORT Item : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Item (NodePtr & d) : Mrl (d, id_node_item) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "item"; } + PlayType playType () { return cached_play_type; } + Mrl * linkNode (); + void closed (); + void activate (); + void deactivate (); + bool handleEvent (EventPtr event); + NodePtrW enclosure; + TimerInfoPtrW timer; +}; + +class KMPLAYER_NO_EXPORT Enclosure : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Enclosure(NodePtr &d) : Mrl(d, id_node_enclosure) {} + KDE_NO_EXPORT const char * nodeName () const { return "enclosure"; } + void closed (); + bool expose () const { return false; } +}; + +} //namespace RSS + + +} // namespace KMPlayer + +#endif //_KMPLAYER_RSS_H_ diff --git a/src/kmplayer_smil.cpp b/src/kmplayer_smil.cpp new file mode 100644 index 0000000..467fbaa --- /dev/null +++ b/src/kmplayer_smil.cpp @@ -0,0 +1,3604 @@ +/** + * Copyright (C) 2005-2007 by Koos Vriezen <[email protected]> + * + * 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 <config.h> + +#include <stdlib.h> + +#include <qtextstream.h> +#include <qcolor.h> +#include <qpixmap.h> +#include <qmovie.h> +#include <qimage.h> +#include <qtextcodec.h> +#include <qfont.h> +#include <qapplication.h> +#include <qregexp.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <kurl.h> +#include <kmimetype.h> +#include <kio/job.h> +#include <kio/jobclasses.h> + +#include "kmplayer_smil.h" +#include "kmplayer_rp.h" + +using namespace KMPlayer; + +namespace KMPlayer { +static const unsigned int event_activated = (unsigned int) Runtime::dur_activated; +const unsigned int event_inbounds = (unsigned int) Runtime::dur_inbounds; +const unsigned int event_outbounds = (unsigned int) Runtime::dur_outbounds; +static const unsigned int event_stopped = (unsigned int) Runtime::dur_end; +static const unsigned int event_started = (unsigned int)Runtime::dur_start; +static const unsigned int event_to_be_started = 1 + (unsigned int) Runtime::dur_last_dur; +const unsigned int event_pointer_clicked = (unsigned int) event_activated; +const unsigned int event_pointer_moved = (unsigned int) -11; +const unsigned int event_timer = (unsigned int) -12; +const unsigned int event_postponed = (unsigned int) -13; +const unsigned int mediatype_attached = (unsigned int) -14; + +static const unsigned int started_timer_id = (unsigned int) 1; +static const unsigned int stopped_timer_id = (unsigned int) 2; +static const unsigned int start_timer_id = (unsigned int) 3; +static const unsigned int dur_timer_id = (unsigned int) 4; +static const unsigned int anim_timer_id = (unsigned int) 5; +static const unsigned int trans_timer_id = (unsigned int) 6; +static const unsigned int trans_out_timer_id = (unsigned int) 7; +} + +/* Intrinsic duration + * duration_time | end_time | + * ======================================================================= + * dur_media | dur_media | wait for event + * 0 | dur_media | only wait for child elements + * dur_media | 0 | intrinsic duration finished + */ +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT bool KMPlayer::parseTime (const QString & vl, int & dur) { + const char * cval = vl.ascii (); + if (!cval) { + dur = 0; + return false; + } + int sign = 1; + bool fp_seen = false; + QString num; + const char * p = cval; + for ( ; *p; p++ ) { + if (*p == '+') { + if (!num.isEmpty ()) + break; + else + sign = 1; + } else if (*p == '-') { + if (!num.isEmpty ()) + break; + else + sign = -1; + } else if (*p >= '0' && *p <= '9') { + num += QChar (*p); + } else if (*p == '.') { + if (fp_seen) + break; + else + num += QChar (*p); + fp_seen = true; + } else if (*p == ' ') { + if (!num.isEmpty ()) + break; + } else + break; + } + bool ok = false; + double t; + if (!num.isEmpty ()) + t = sign * num.toDouble (&ok); + if (ok) { + dur = (unsigned int) (10 * t); + for ( ; *p; p++ ) { + if (*p == 'm') { + dur = (unsigned int) (t * 60); + break; + } else if (*p == 'h') { + dur = (unsigned int) (t * 60 * 60); + break; + } else if (*p != ' ') + break; + } + } else { + dur = 0; + return false; + } + return true; +} + +static SMIL::Region * findRegion (NodePtr p, const QString & id) { + TrieString regionname_attr ("regionName"); + for (NodePtr c = p->firstChild (); c; c = c->nextSibling ()) { + if (c->id == SMIL::id_node_region) { + SMIL::Region * r = convertNode <SMIL::Region> (c); + QString a = r->getAttribute (regionname_attr); + if (a.isEmpty ()) + a = r->getAttribute (StringPool::attr_id); + if ((a.isEmpty () && id.isEmpty ()) || a == id) { + //kdDebug () << "MediaType region found " << id << endl; + return r; + } + } + SMIL::Region * r = findRegion (c, id); + if (r) + return r; + } + return 0L; +} + +static SMIL::Transition * findTransition (NodePtr n, const QString & id) { + SMIL::Smil * s = SMIL::Smil::findSmilNode (n); + if (s) { + Node * head = s->firstChild ().ptr (); + while (head && head->id != SMIL::id_node_head) + head = head->nextSibling ().ptr (); + if (head) + for (Node * c = head->firstChild (); c; c = c->nextSibling().ptr ()) + if (c->id == SMIL::id_node_transition && + id == static_cast <Element *> (c)-> + getAttribute (StringPool::attr_id)) + return static_cast <SMIL::Transition *> (c); + } + return 0L; +} + +static NodePtr findLocalNodeById (NodePtr n, const QString & id) { + //kdDebug() << "findLocalNodeById " << id << endl; + SMIL::Smil * s = SMIL::Smil::findSmilNode (n); + if (s) + return s->document ()->getElementById (s, id, false); + return 0L; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT ToBeStartedEvent::ToBeStartedEvent (NodePtr n) + : Event (event_to_be_started), node (n) {} + +TimerEvent::TimerEvent (TimerInfoPtr tinfo) + : Event (event_timer), timer_info (tinfo), interval (false) {} + +PostponedEvent::PostponedEvent (bool postponed) + : Event (event_postponed), is_postponed (postponed) {} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT Runtime::Runtime (NodePtr e) + : timingstate (timings_reset), + element (e), repeat_count (0) {} + +KDE_NO_CDTOR_EXPORT Runtime::~Runtime () { + if (start_timer || duration_timer) // ugh + reset (); +} + +KDE_NO_EXPORT void Runtime::reset () { + if (element) { + if (start_timer) { + element->document ()->cancelTimer (start_timer); + ASSERT (!start_timer); + } + if (duration_timer) { + element->document ()->cancelTimer (duration_timer); + ASSERT (!duration_timer); + } + } else { + start_timer = 0L; + duration_timer = 0L; + } + repeat_count = 0; + timingstate = timings_reset; + for (int i = 0; i < (int) durtime_last; i++) { + if (durations [i].connection) + durations [i].connection->disconnect (); + durations [i].durval = dur_timer; + durations [i].offset = 0; + } + endTime ().durval = dur_media; +} + +KDE_NO_EXPORT +void Runtime::setDurationItem (DurationTime item, const QString & val) { + int dur = -2; // also 0 for 'media' duration, so it will not update then + QString vs = val.stripWhiteSpace (); + QString vl = vs.lower (); + const char * cval = vl.ascii (); + int offset = 0; + //kdDebug () << "setDuration1 " << vl << endl; + if (cval && cval[0]) { + QString idref; + const char * p = cval; + if (parseTime (vl, offset)) { + dur = dur_timer; + } else if (!strncmp (cval, "id(", 3)) { + p = strchr (cval + 3, ')'); + if (p) { + idref = vs.mid (3, p - cval - 3); + p++; + } + if (*p) { + const char *q = strchr (p, '('); + if (q) + p = q; + } + } else if (!strncmp (cval, "indefinite", 10)) { + dur = dur_infinite; + } else if (!strncmp (cval, "media", 5)) { + dur = dur_media; + } + if (dur == -2) { + NodePtr target; + const char * q = p; + if (idref.isEmpty ()) { + bool last_esc = false; + for ( ; *q; q++) { + if (*q == '\\') { + if (last_esc) { + idref += QChar ('\\'); + last_esc = false; + } else + last_esc = true; + } else if (*q == '.' && !last_esc) { + break; + } else + idref += QChar (*q); + } + if (!*q) + idref = vs.mid (p - cval); + else + idref = vs.mid (p - cval, q - p); + } + ++q; + if (!idref.isEmpty ()) { + target = findLocalNodeById (element, idref); + if (!target) + kdWarning () << "Element not found " << idref << endl; + } + //kdDebug () << "setDuration q:" << q << endl; + if (parseTime (vl.mid (q-cval), offset)) { + dur = dur_start; + } else if (*q && !strncmp (q, "end", 3)) { + dur = dur_end; + parseTime (vl.mid (q + 3 - cval), offset); + } else if (*q && !strncmp (q, "begin", 5)) { + dur = dur_start; + parseTime (vl.mid (q + 5 - cval), offset); + } else if (*q && !strncmp (q, "activateevent", 13)) { + dur = dur_activated; + parseTime (vl.mid (q + 13 - cval), offset); + } else if (*q && !strncmp (q, "inboundsevent", 13)) { + dur = dur_inbounds; + parseTime (vl.mid (q + 13 - cval), offset); + } else if (*q && !strncmp (q, "outofboundsevent", 16)) { + dur = dur_outbounds; + parseTime (vl.mid (q + 16 - cval), offset); + } else + kdWarning () << "setDuration no match " << cval << endl; + if (target && dur != dur_timer) { + durations [(int) item].connection = + target->connectTo (element, dur); + } + } + //kdDebug () << "setDuration " << dur << " id:'" << idref << "' off:" << offset << endl; + } + durations [(int) item].durval = (Duration) dur; + durations [(int) item].offset = offset; +} + +/** + * start, or restart in case of re-use, the durations + */ +KDE_NO_EXPORT void Runtime::begin () { + if (!element) { + reset (); + return; + } + //kdDebug () << "Runtime::begin " << element->nodeName() << endl; + if (start_timer || duration_timer) + convertNode <SMIL::TimedMrl> (element)->init (); + timingstate = timings_began; + + int offset = 0; + bool stop = true; + if (beginTime ().durval == dur_start) { // check started/finished + Connection * con = beginTime ().connection.ptr (); + if (con && con->connectee && + con->connectee->state >= Node::state_began) { + offset = beginTime ().offset; + if (SMIL::TimedMrl::isTimedMrl (con->connectee)) + offset -= element->document ()->last_event_time - + convertNode <SMIL::TimedMrl>(con->connectee)->begin_time; + stop = false; + kdWarning() << "start trigger on started element" << endl; + } // else wait for start event + } else if (beginTime ().durval == dur_end) { // check finished + Connection * con = beginTime ().connection.ptr (); + if (con && con->connectee && + con->connectee->state >= Node::state_finished) { + int offset = beginTime ().offset; + if (SMIL::TimedMrl::isTimedMrl (con->connectee)) + offset -= element->document ()->last_event_time - + convertNode<SMIL::TimedMrl>(con->connectee)->finish_time; + stop = false; + kdWarning() << "start trigger on finished element" << endl; + } // else wait for end event + } else if (beginTime ().durval == dur_timer) { + offset = beginTime ().offset; + stop = false; + } + if (stop) // wait for event + propagateStop (false); + else if (offset > 0) // start timer + start_timer = element->document ()->setTimeout ( + element, 100 * offset, start_timer_id); + else // start now + propagateStart (); +} + +KDE_NO_EXPORT void Runtime::beginAndStart () { + if (element) { + if (start_timer || duration_timer) + convertNode <SMIL::TimedMrl> (element)->init (); + timingstate = timings_began; + propagateStart (); + } +} + +KDE_NO_EXPORT +bool Runtime::parseParam (const TrieString & name, const QString & val) { + //kdDebug () << "Runtime::parseParam " << name << "=" << val << endl; + if (name == StringPool::attr_begin) { + setDurationItem (begin_time, val); + if ((timingstate == timings_began && !start_timer) || + timingstate == timings_stopped) { + if (beginTime ().offset > 0) { // create a timer for start + if (start_timer) + element->document ()->cancelTimer (start_timer); + if (beginTime ().durval == dur_timer) + start_timer = element->document ()->setTimeout + (element, 100 * beginTime ().offset, start_timer_id); + } else // start now + propagateStart (); + } + } else if (name == StringPool::attr_dur) { + setDurationItem (duration_time, val); + } else if (name == StringPool::attr_end) { + setDurationItem (end_time, val); + if (endTime ().durval == dur_timer && + endTime ().offset > beginTime ().offset) + durTime ().offset = endTime ().offset - beginTime ().offset; + else if (endTime ().durval != dur_timer) + durTime ().durval = dur_media; // event + } else if (name == StringPool::attr_title) { + Mrl * mrl = static_cast <Mrl *> (element.ptr ()); + if (mrl) + mrl->pretty_name = val; + } else if (name == "endsync") { + if ((durTime ().durval == dur_media || durTime ().durval == 0) && + endTime ().durval == dur_media) { + NodePtr e = findLocalNodeById (element, val); + if (SMIL::TimedMrl::isTimedMrl (e)) { + SMIL::TimedMrl * tm = static_cast <SMIL::TimedMrl *> (e.ptr ()); + durations [(int) end_time].connection = + tm->connectTo (element, event_stopped); + durations [(int) end_time].durval = (Duration) event_stopped; + } + } + } else if (name.startsWith ("repeat")) { + if (val.find ("indefinite") > -1) + repeat_count = dur_infinite; + else + repeat_count = val.toInt (); + } else + return false; + return true; +} + +KDE_NO_EXPORT void Runtime::processEvent (unsigned int event) { + SMIL::TimedMrl * tm = convertNode <SMIL::TimedMrl> (element); + if (tm) { + if (timingstate != timings_started && beginTime ().durval == event) { + if (start_timer) + element->document ()->cancelTimer (start_timer); + if (element && beginTime ().offset > 0) + start_timer = element->document ()->setTimeout (element, + 100 * beginTime ().offset, start_timer_id); + else //FIXME neg. offsets + propagateStart (); + if (tm->state == Node::state_finished) + tm->state = Node::state_activated; // rewind to activated + } else if (timingstate == timings_started && + (unsigned int) endTime ().durval == event) + propagateStop (true); + } else + reset (); +} + +KDE_NO_EXPORT void Runtime::propagateStop (bool forced) { + if (state() == timings_reset || state() == timings_stopped) + return; // nothing to stop + if (!forced && element) { + if (durTime ().durval == dur_media && endTime ().durval == dur_media) + return; // wait for external eof + if (endTime ().durval != dur_timer && endTime ().durval != dur_media && + (state() == timings_started || beginTime().durval == dur_timer)) + return; // wait for event + if (durTime ().durval == dur_infinite) + return; // this may take a while :-) + if (duration_timer) + return; // timerEvent will call us with forced=true + // bail out if a child still running + for (NodePtr c = element->firstChild (); c; c = c->nextSibling ()) + if (c->unfinished ()) + return; // a child still running + } + bool was_started (timingstate == timings_started); + timingstate = timings_stopped; + if (element) { + if (start_timer) { + element->document ()->cancelTimer (start_timer); + ASSERT (!start_timer); + } + if (duration_timer) { + element->document ()->cancelTimer (duration_timer); + ASSERT (!duration_timer); + } + if (was_started && element->document ()->active ()) + element->document ()->setTimeout (element, 0, stopped_timer_id); + else if (element->unfinished ()) + element->finish (); + } else { + start_timer = 0L; + duration_timer = 0L; + } +} + +KDE_NO_EXPORT void Runtime::propagateStart () { + SMIL::TimedMrl * tm = convertNode <SMIL::TimedMrl> (element); + if (tm) { + tm->propagateEvent (new ToBeStartedEvent (element)); + if (start_timer) + tm->document ()->cancelTimer (start_timer); + ASSERT (!start_timer); + } else + start_timer = 0L; + timingstate = timings_started; + element->document ()->setTimeout (element, 0, started_timer_id); +} + +/** + * start_timer timer expired + */ +KDE_NO_EXPORT void Runtime::started () { + //kdDebug () << "Runtime::started " << (element ? element->nodeName() : "-") << endl; + NodePtr e = element; // element is weak + SMIL::TimedMrl * tm = convertNode <SMIL::TimedMrl> (e); + if (tm) { + if (start_timer) + tm->document ()->cancelTimer (start_timer); + if (durTime ().offset > 0 && durTime ().durval == dur_timer) { + if (duration_timer) + tm->document ()->cancelTimer (duration_timer); + duration_timer = element->document ()->setTimeout + (element, 100 * durTime ().offset, dur_timer_id); + } + // kdDebug () << "Runtime::started set dur timer " << durTime ().offset << endl; + tm->propagateEvent (new Event (event_started)); + tm->begin (); + } else + reset (); +} + +/** + * duration_timer timer expired or no duration set after started + */ +KDE_NO_EXPORT void Runtime::stopped () { + if (!element) { + reset (); + } else if (element->active ()) { + if (repeat_count == dur_infinite || 0 < repeat_count--) { + if (beginTime ().offset > 0 && + beginTime ().durval == dur_timer) { + if (start_timer) + element->document ()->cancelTimer (start_timer); + start_timer = element->document ()->setTimeout + (element, 100 * beginTime ().offset, start_timer_id); + } else { + propagateStart (); + } + } else { + repeat_count = 0; + element->finish (); + } + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SizeType::SizeType () { + reset (); +} + +KDE_NO_CDTOR_EXPORT SizeType::SizeType (const QString & s) { + *this = s; +} + +void SizeType::reset () { + perc_size = 0; + abs_size = 0; + isset = false; +} + +SizeType & SizeType::operator = (const QString & s) { + QString strval (s); + int p = strval.find (QChar ('%')); + if (p > -1) { + strval.truncate (p); + perc_size = strval.toDouble (&isset); + } else + abs_size = strval.toDouble (&isset); + return *this; +} + +SizeType & SizeType::operator += (const SizeType & s) { + perc_size += s.perc_size; + abs_size += s.abs_size; + return *this; +} + +SizeType & SizeType::operator -= (const SizeType & s) { + perc_size -= s.perc_size; + abs_size -= s.abs_size; + return *this; +} + +Single SizeType::size (Single relative_to) const { + Single s = abs_size; + s += perc_size * relative_to / 100; + return s; +} + +//-----------------%<---------------------------------------------------------- + +SRect SRect::unite (const SRect & r) const { + if (!(_w > 0 && _h > 0)) + return r; + if (!(r._w > 0 && r._h > 0)) + return *this; + Single a (_x < r._x ? _x : r._x); + Single b (_y < r._y ? _y : r._y); + return SRect (a, b, + ((_x + _w < r._x + r._w) ? r._x + r._w : _x + _w) - a, + ((_y + _h < r._y + r._h) ? r._y + r._h : _y + _h) - b); +} + +SRect SRect::intersect (const SRect & r) const { + Single a (_x < r._x ? r._x : _x); + Single b (_y < r._y ? r._y : _y); + return SRect (a, b, + ((_x + _w < r._x + r._w) ? _x + _w : r._x + r._w) - a, + ((_y + _h < r._y + r._h) ? _y + _h : r._y + r._h) - b); +} + +IRect IRect::unite (const IRect & r) const { + if (isEmpty ()) + return r; + if (r.isEmpty ()) + return *this; + int a (x < r.x ? x : r.x); + int b (y < r.y ? y : r.y); + return IRect (a, b, + ((x + w < r.x + r.w) ? r.x + r.w : x + w) - a, + ((y + h < r.y + r.h) ? r.y + r.h : y + h) - b); +} + +IRect IRect::intersect (const IRect & r) const { + int a (x < r.x ? r.x : x); + int b (y < r.y ? r.y : y); + return IRect (a, b, + ((x + w < r.x + r.w) ? x + w : r.x + r.w) - a, + ((y + h < r.y + r.h) ? y + h : r.y + r.h) - b); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void CalculatedSizer::resetSizes () { + left.reset (); + top.reset (); + width.reset (); + height.reset (); + right.reset (); + bottom.reset (); + reg_point.truncate (0); + reg_align = QString::fromLatin1 ("topLeft"); +} + +static bool regPoints (const QString & str, Single & x, Single & y) { + QString lower = str.lower (); + const char * rp = lower.ascii (); + if (!rp) + return false; + if (!strcmp (rp, "center")) { + x = 50; + y = 50; + } else { + if (!strncmp (rp, "top", 3)) { + y = 0; + rp += 3; + } else if (!strncmp (rp, "mid", 3)) { + y = 50; + rp += 3; + } else if (!strncmp (rp, "bottom", 6)) { + y = 100; + rp += 6; + } else + return false; + if (!strcmp (rp, "left")) { + x = 0; + } else if (!strcmp (rp, "mid")) { + x = 50; + } else if (!strcmp (rp, "right")) { + x = 100; + } else + return false; + } + return true; +} + +KDE_NO_EXPORT +bool CalculatedSizer::applyRegPoints (Node * node, Single w, Single h, + Single & xoff, Single & yoff, Single & w1, Single & h1) { + if (reg_point.isEmpty ()) + return false; + Single rpx, rpy, rax, ray; + if (!regPoints (reg_point, rpx, rpy)) { + node = SMIL::Smil::findSmilNode (node); + if (!node) + return false; + node = static_cast <SMIL::Smil *> (node)->layout_node.ptr (); + if (!node) + return false; + NodePtr c = node->firstChild (); + for (; c; c = c->nextSibling ()) + if (c->id == SMIL::id_node_regpoint && + convertNode<Element>(c)->getAttribute (StringPool::attr_id) + == reg_point) { + Single i1, i2; // dummies + SMIL::RegPoint *rp_elm = static_cast<SMIL::RegPoint*>(c.ptr()); + rp_elm->sizes.calcSizes (0L, 100, 100, rpx, rpy, i1, i2); + QString ra = rp_elm->getAttribute ("regAlign"); + if (!ra.isEmpty () && reg_align.isEmpty ()) + reg_align = ra; + break; + } + if (!c) + return false; // not found + } + if (!regPoints (reg_align, rax, ray)) + rax = ray = 0; // default back to topLeft + if (!(int)w1 || !(int)h1) { + xoff = w * (rpx - rax) / 100; + yoff = h * (rpy - ray) / 100; + w1 = w - w * (rpx > rax ? (rpx - rax) : (rax - rpx)) / 100; + h1 = h - h * (rpy > ray ? (rpy - ray) : (ray - rpy)) / 100; + } else { + xoff = (w * rpx - w1 * rax) / 100; + yoff = (h * rpy - h1 * ray) / 100; + } + // kdDebug () << "calc rp:" << reg_point << " ra:" << reg_align << " w:" << (int)w << " h:" << (int)h << " xoff:" << (int)xoff << " yoff:" << (int)yoff << " w1:" << (int)w1 << " h1:" << (int)h1 << endl; + return true; // success getting sizes based on regPoint +} + +KDE_NO_EXPORT void CalculatedSizer::calcSizes (Node * node, Single w, Single h, + Single & xoff, Single & yoff, Single & w1, Single & h1) { + if (applyRegPoints (node, w, h, xoff, yoff, w1, h1)) + return; + if (left.isSet ()) + xoff = left.size (w); + else if (width.isSet ()) { + if (right.isSet ()) + xoff = w - width.size (w) - right.size (w); + else + xoff = (w - width.size (w)) / 2; + } else + xoff = 0; + if (top.isSet ()) + yoff = top.size (h); + else if (height.isSet ()) { + if (bottom.isSet ()) + yoff = h - height.size (h) - bottom.size (h); + else + yoff = (h - height.size (h)) / 2; + } else + yoff = 0; + if (width.isSet ()) + w1 = width.size (w); + else if (right.isSet ()) + w1 = w - xoff - right.size (w); + else + w1 = w - xoff; + if (w1 < 0) + w1 = 0; + if (height.isSet ()) + h1 = height.size (h); + else if (bottom.isSet ()) + h1 = h - yoff - bottom.size (h); + else + h1 = h - yoff; + if (h1 < 0) + h1 = 0; +} + +KDE_NO_EXPORT +bool CalculatedSizer::setSizeParam(const TrieString &name, const QString &val, bool &dim_changed) { + dim_changed = true; + if (name == StringPool::attr_left) { + left = val; + dim_changed = right.isSet (); + } else if (name == StringPool::attr_top) { + top = val; + dim_changed = bottom.isSet (); + } else if (name == StringPool::attr_width) { + width = val; + } else if (name == StringPool::attr_height) { + height = val; + } else if (name == StringPool::attr_right) { + right = val; + dim_changed = left.isSet (); + } else if (name == StringPool::attr_bottom) { + bottom = val; + dim_changed = top.isSet (); + } else if (name == "regPoint") { + reg_point = val; + dim_changed = false; + } else if (name == "regAlign") { + reg_align = val; + dim_changed = false; + } else + return false; + return true; +} + +KDE_NO_EXPORT void +CalculatedSizer::move (const SizeType &x, const SizeType &y) { + if (left.isSet ()) { + if (right.isSet ()) { + right += x; + right -= left; + } + left = x; + } else if (right.isSet ()) { + right = x; + } else { + left = x; + } + if (top.isSet ()) { + if (bottom.isSet ()) { + bottom += y; + bottom -= top; + } + top = y; + } else if (bottom.isSet ()) { + bottom = y; + } else { + top = y; + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT AnimateGroupData::AnimateGroupData (NodePtr e) + : Runtime (e), modification_id (-1) {} + +bool AnimateGroupData::parseParam (const TrieString &name, const QString &val) { + //kdDebug () << "AnimateGroupData::parseParam " << name << "=" << val << endl; + if (name == StringPool::attr_target || name == "targetElement") { + if (element) + target_element = findLocalNodeById (element, val); + } else if (name == "attribute" || name == "attributeName") { + changed_attribute = TrieString (val); + } else if (name == "to") { + change_to = val; + } else + return Runtime::parseParam (name, val); + return true; +} + +/** + * animation finished + */ +KDE_NO_EXPORT void AnimateGroupData::stopped () { + //kdDebug () << "AnimateGroupData::stopped " << durTime ().durval << endl; + if (!SMIL::TimedMrl::keepContent (element)) + restoreModification (); + Runtime::stopped (); +} + +KDE_NO_EXPORT void AnimateGroupData::reset () { + restoreModification (); + Runtime::reset (); +} + +KDE_NO_EXPORT void AnimateGroupData::restoreModification () { + if (modification_id > -1 && target_element && + target_element->state > Node::state_init) { + //kdDebug () << "AnimateGroupData(" << this << ")::restoreModificatio " <<modification_id << endl; + convertNode <Element> (target_element)->resetParam ( + changed_attribute, modification_id); + } + modification_id = -1; +} + +//----------------------------------------------------------------------------- + +/** + * start_timer timer expired, execute it + */ +KDE_NO_EXPORT void SetData::started () { + restoreModification (); + if (element) { + if (target_element) { + convertNode <Element> (target_element)->setParam ( + changed_attribute, change_to, &modification_id); + //kdDebug () << "SetData(" << this << ")::started " << target_element->nodeName () << "." << changed_attribute << " ->" << change_to << " modid:" << modification_id << endl; + } else + kdWarning () << "target element not found" << endl; + } else + kdWarning () << "set element disappeared" << endl; + AnimateGroupData::started (); +} + +//----------------------------------------------------------------------------- + +//http://en.wikipedia.org/wiki/B%C3%A9zier_curve +typedef struct { + float x; + float y; +} Point2D; + +static Point2D PointOnCubicBezier (Point2D *cp, float t) { + float ax, bx, cx; + float ay, by, cy; + float tSquared, tCubed; + Point2D result; + + /* calculate the polynomial coefficients */ + + cx = 3.0 * (cp[1].x - cp[0].x); + bx = 3.0 * (cp[2].x - cp[1].x) - cx; + ax = cp[3].x - cp[0].x - cx - bx; + + cy = 3.0 * (cp[1].y - cp[0].y); + by = 3.0 * (cp[2].y - cp[1].y) - cy; + ay = cp[3].y - cp[0].y - cy - by; + + /* calculate the curve point at parameter value t */ + + tSquared = t * t; + tCubed = tSquared * t; + + result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x; + result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y; + + return result; +} + +KDE_NO_CDTOR_EXPORT AnimateData::AnimateData (NodePtr e) + : AnimateGroupData (e), change_by (0), steps (0) {} + +KDE_NO_EXPORT void AnimateData::reset () { + AnimateGroupData::reset (); + if (element) { + if (anim_timer) + element->document ()->cancelTimer (anim_timer); + ASSERT (!anim_timer); + } else + anim_timer = 0; + accumulate = acc_none; + additive = add_replace; + change_by = 0; + calcMode = calc_linear; + change_from.truncate (0); + change_values.clear (); + steps = 0; + change_delta = change_to_val = change_from_val = 0.0; + change_from_unit.truncate (0); +} + +bool AnimateData::parseParam (const TrieString & name, const QString & val) { + //kdDebug () << "AnimateData::parseParam " << name << "=" << val << endl; + if (name == "change_by") { + change_by = val.toInt (); + } else if (name == "from") { + change_from = val; + } else if (name == "values") { + change_values = QStringList::split (QString (";"), val); + } else if (name == "calcMode") { + if (val == QString::fromLatin1 ("discrete")) + calcMode = calc_discrete; + else if (val == QString::fromLatin1 ("linear")) + calcMode = calc_linear; + else if (val == QString::fromLatin1 ("paced")) + calcMode = calc_paced; + } else + return AnimateGroupData::parseParam (name, val); + return true; +} + +/** + * start_timer timer expired, execute it + */ +KDE_NO_EXPORT void AnimateData::started () { + //kdDebug () << "AnimateData::started " << durTime ().durval << endl; + restoreModification (); + if (anim_timer) { + kdWarning () << "AnimateData::started " << anim_timer.ptr() << endl; + element->document ()->cancelTimer (anim_timer); + } + bool success = false; + do { + if (!element) { + kdWarning () << "set element disappeared" << endl; + break; + } + NodePtr protect = target_element; + Element * target = convertNode <Element> (target_element); + if (!target) { + kdWarning () << "target element not found" << endl; + break; + } + if (calcMode == calc_linear) { + QRegExp reg ("^\\s*(-?[0-9\\.]+)(\\s*[%a-z]*)?"); + if (change_from.isEmpty ()) { + if (change_values.size () > 0) // check 'values' attribute + change_from = change_values.first (); + else // take current + change_from = target->param (changed_attribute); + } + if (!change_from.isEmpty ()) { + target->setParam (changed_attribute, change_from, + &modification_id); + if (reg.search (change_from) > -1) { + change_from_val = reg.cap (1).toDouble (); + change_from_unit = reg.cap (2); + } + } else { + kdWarning() << "animate couldn't determine start value" << endl; + break; + } + if (change_to.isEmpty () && change_values.size () > 1) + change_to = change_values.last (); // check 'values' attribute + if (!change_to.isEmpty () && reg.search (change_to) > -1) { + change_to_val = reg.cap (1).toDouble (); + } else { + kdWarning () << "animate couldn't determine end value" << endl; + break; + } + steps = 20 * durTime ().offset / 5; // 40 per sec + if (steps > 0) { + anim_timer = element->document ()->setTimeout (element, 25, anim_timer_id); // 25 ms for now FIXME + change_delta = (change_to_val - change_from_val) / steps; + //kdDebug () << "AnimateData::started " << target_element->nodeName () << "." << changed_attribute << " " << change_from_val << "->" << change_to_val << " in " << steps << " using:" << change_delta << " inc" << endl; + success = true; + } + } else if (calcMode == calc_discrete) { + steps = change_values.size () - 1; // we do already the first step + if (steps < 1) { + kdWarning () << "animate needs at least two values" << endl; + break; + } + int interval = 100 * durTime ().offset / (1 + steps); + if (interval <= 0 || durTime ().durval != dur_timer) { + kdWarning () << "animate needs a duration time" << endl; + break; + } + //kdDebug () << "AnimateData::started " << target_element->nodeName () << "." << changed_attribute << " " << change_values.first () << "->" << change_values.last () << " in " << steps << " interval:" << interval << endl; + anim_timer = element->document ()->setTimeout (element, interval, anim_timer_id); // 50 /s for now FIXME + target->setParam (changed_attribute, change_values.first (), + &modification_id); + success = true; + } + } while (false); + if (success) + AnimateGroupData::started (); + else + propagateStop (true); +} + +/** + * undo if necessary + */ +KDE_NO_EXPORT void AnimateData::stopped () { + if (element) { + if (anim_timer) // make sure timers are stopped + element->document ()->cancelTimer (anim_timer); + ASSERT (!anim_timer); + if (steps > 0 && element->active ()) { + steps = 0; + if (calcMode == calc_linear) + change_from_val = change_to_val; + applyStep (); // we lost some steps .. + } + } else + anim_timer = 0; + AnimateGroupData::stopped (); +} + +KDE_NO_EXPORT void AnimateData::applyStep () { + Element * target = convertNode <Element> (target_element); + if (target && calcMode == calc_linear) + target->setParam (changed_attribute, QString ("%1%2").arg ( + change_from_val).arg(change_from_unit), + &modification_id); + else if (target && calcMode == calc_discrete) + target->setParam (changed_attribute, + change_values[change_values.size () - steps -1], + &modification_id); +} + +/** + * for animations + */ +KDE_NO_EXPORT bool AnimateData::timerTick () { + if (!anim_timer) { + kdError () << "spurious anim timer tick" << endl; + } else if (steps-- > 0) { + if (calcMode == calc_linear) + change_from_val += change_delta; + applyStep (); + return true; + } else { + if (element) + element->document ()->cancelTimer (anim_timer); + ASSERT (!anim_timer); + propagateStop (true); // not sure, actually + } + return false; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT AnimateMotionData::AnimateMotionData (NodePtr e) + : AnimateGroupData (e), keytimes (NULL), steps (0) {} + +KDE_NO_CDTOR_EXPORT AnimateMotionData::~AnimateMotionData () { + reset (); +} + +bool AnimateMotionData::checkTarget (Node *n) { + if (!n || + (SMIL::id_node_region != n->id && + !(SMIL::id_node_first_mediatype <= n->id && + SMIL::id_node_last_mediatype >= n->id))) { + kdWarning () << "animateMotion target element not " << + (n ? "supported" : "found") << endl; + if (element && anim_timer) + element->document ()->cancelTimer (anim_timer); + propagateStop (true); + return false; + } + return true; +} + +KDE_NO_EXPORT void AnimateMotionData::reset () { + AnimateGroupData::reset (); + if (element) { + if (anim_timer) + element->document ()->cancelTimer (anim_timer); + ASSERT (!anim_timer); + } else + anim_timer = 0; + accumulate = acc_none; + additive = add_replace; + calcMode = calc_linear; + change_from.truncate (0); + change_by.truncate (0); + values.clear (); + delete keytimes; + keytimes = NULL; + keytime_count = 0; + splines.clear (); + steps = 0; + cur_x = cur_y = delta_x = delta_y = SizeType(); +} + +bool AnimateMotionData::parseParam (const TrieString & name, const QString & val) { + //kdDebug () << "AnimateMotionData::parseParam " << name << "=" << val << endl; + if (name == "from") { + change_from = val; + } else if (name == "by") { + change_by = val; + } else if (name == "values") { + values = QStringList::split (QString (";"), val); + } else if (name == "keyTimes") { + QStringList kts = QStringList::split (QString (";"), val); + delete keytimes; + keytime_count = kts.size (); + keytimes = new float [keytime_count]; + for (int i = 0; i < keytime_count; i++) { + keytimes[i] = kts[i].stripWhiteSpace().toDouble(); + if (keytimes[i] < 0.0 || keytimes[i] > 1.0) + kdWarning() << "animateMotion wrong keyTimes values" << endl; + else if (i == 0 && keytimes[i] > 0.01) + kdWarning() << "animateMotion first keyTimes value not 0" << endl; + else + continue; + delete keytimes; + keytimes = NULL; + keytime_count = 0; + return true; + } + } else if (name == "keySplines") { + splines = QStringList::split (QString (";"), val); + } else if (name == "calcMode") { + if (val == QString::fromLatin1 ("discrete")) + calcMode = calc_discrete; + else if (val == QString::fromLatin1 ("linear")) + calcMode = calc_linear; + else if (val == QString::fromLatin1 ("paced")) + calcMode = calc_paced; + else if (val == QString::fromLatin1 ("spline")) + calcMode = calc_spline; + } else + return AnimateGroupData::parseParam (name, val); + return true; +} + +bool AnimateMotionData::getCoordinates (const QString &coord, SizeType &x, SizeType &y) { + int p = coord.find (QChar (',')); + if (p > 0) { + x = coord.left (p).stripWhiteSpace (); + y = coord.mid (p + 1).stripWhiteSpace (); + return true; + } + return false; +} + +bool AnimateMotionData::setInterval () { + int cs = 10 * durTime ().offset; + if (keytime_count > interval + 1) + cs = (int) (cs * (keytimes[interval+1] - keytimes[interval])); + else if (values.size () > 1) + cs /= values.size () - 1; + if (cs < 0) { + kdWarning () << "animateMotion has no valid duration interval " << + interval << endl; + propagateStop (true); + return false; + } + steps = cs * 4 / 10; // 40 per sec + cur_step = 0; + cur_x = begin_x; + cur_y = begin_y; + delta_x = end_x; + delta_x -= begin_x; + delta_y = end_y; + delta_y -= begin_y; + switch (calcMode) { + case calc_paced: // FIXME + case calc_linear: + delta_x /= steps; + delta_y /= steps; + break; + case calc_spline: + if (splines.size () > interval) { + QStringList kss = QStringList::split ( + QString (" "), splines[interval]); + control_point[0] = control_point[1] = 0; + control_point[2] = control_point[3] = 1; + if (kss.size () == 4) { + for (int i = 0; i < 4; ++i) { + control_point[i] = kss[i].toDouble(); + if (control_point[i] < 0 || control_point[i] > 1) { + kdWarning () << "keySplines values not between 0-1" + << endl; + control_point[i] = i > 1 ? 1 : 0; + break; + } + } + } else { + kdWarning () << "keySplines " << interval << + " has not 4 values" << endl; + } + } + break; + default: + break; + } + //kdDebug() << "setInterval " << steps << " " << + // cur_x.size() << "," << cur_y.size() << "=>" + // << end_x.size() << "," << end_y.size() << " d:" << + // delta_x.size() << "," << delta_y.size() << endl; + return true; +} + +KDE_NO_EXPORT void AnimateMotionData::started () { + //kdDebug () << "AnimateMotionData::started " << durTime ().durval << endl; + Element *target = convertNode <Element> (target_element); + if (!element || !checkTarget (target)) + return; + if (anim_timer) + element->document ()->cancelTimer (anim_timer); + interval = 0; + if (change_from.isEmpty ()) { + if (values.size () > 1) { + getCoordinates (values[0], begin_x, begin_y); + getCoordinates (values[1], end_x, end_y); + } else { + CalculatedSizer sizes; + if (SMIL::id_node_region == target->id) + sizes = static_cast<SMIL::Region*>(target)->sizes; + else if (SMIL::id_node_first_mediatype <= target->id && + SMIL::id_node_last_mediatype >= target->id) + sizes = static_cast<SMIL::MediaType*>(target)->sizes; + if (sizes.left.isSet ()) { + begin_x = sizes.left; + } else if (sizes.right.isSet() && sizes.width.isSet ()) { + begin_x = sizes.right; + begin_x -= sizes.width; + } else { + begin_x = "0"; + } + if (sizes.top.isSet ()) { + begin_y = sizes.top; + } else if (sizes.bottom.isSet() && sizes.height.isSet ()) { + begin_y = sizes.bottom; + begin_y -= sizes.height; + } else { + begin_y = "0"; + } + } + } else { + getCoordinates (change_from, begin_x, begin_y); + } + if (!change_by.isEmpty ()) { + getCoordinates (change_by, delta_x, delta_y); + end_x = begin_x; + end_y = begin_y; + end_x += delta_x; + end_y += delta_y; + } else if (!change_to.isEmpty ()) { + getCoordinates (change_to, end_x, end_y); + } + if (!setInterval ()) + return; + applyStep (); + anim_timer = element->document ()->setTimeout (element, 25, anim_timer_id); + AnimateGroupData::started (); +} + + +KDE_NO_EXPORT void AnimateMotionData::stopped () { + if (element) { + if (anim_timer) // make sure timers are stopped + element->document ()->cancelTimer (anim_timer); + ASSERT (!anim_timer); + if (cur_step < steps && element->active () || + (interval > 1 && calcMode == calc_discrete)) { + steps = 0; + if (cur_x.size () != end_x.size () || + cur_y.size () != end_y.size ()) { + cur_x = end_x; + cur_y = end_y; + applyStep (); // we lost some steps .. + } + } + } else + anim_timer = 0; + AnimateGroupData::stopped (); +} + +KDE_NO_EXPORT void AnimateMotionData::applyStep () { + Node *target = target_element.ptr (); + if (!checkTarget (target)) + return; + if (SMIL::id_node_region == target->id) { + SMIL::Region* r = static_cast <SMIL::Region*> (target); + if (r->surface ()) { + r->sizes.move (cur_x, cur_y); + r->boundsUpdate (); + } + } else { + SMIL::MediaType *mt = static_cast <SMIL::MediaType *> (target); + if (mt->surface ()) { + mt->sizes.move (cur_x, cur_y); + mt->boundsUpdate (); + } + } +} + +KDE_NO_EXPORT bool AnimateMotionData::timerTick () { + if (!anim_timer) { + kdError () << "spurious animateMotion timer tick" << endl; + } else if (cur_step++ < steps) { + switch (calcMode) { + case calc_paced: // FIXME + case calc_linear: + cur_x += delta_x; + cur_y += delta_y; + break; + case calc_spline: { + Point2D ps[4] = { + { 0, 0 }, + { control_point[0], control_point[1] }, + { control_point[2], control_point[3] }, + { 1, 1 } + }; + Point2D p = PointOnCubicBezier (ps, 1.0 * cur_step / steps); + cur_x = delta_x; + cur_y = delta_y; + cur_x *= p.y; + cur_y *= p.y; + cur_x += begin_x; + cur_y += begin_y; + break; + } + case calc_discrete: + return true; // very sub-optimal timer + } + applyStep (); + return true; + } else if (values.size () > ++interval + 1) { + getCoordinates (values[interval], begin_x, begin_y); + getCoordinates (values[interval+1], end_x, end_y); + if (setInterval ()) { + applyStep (); + return true; + } + } + anim_timer = NULL; + return false; +} + +//----------------------------------------------------------------------------- + +static NodePtr findExternalTree (NodePtr mrl) { + for (NodePtr c = mrl->firstChild (); c; c = c->nextSibling ()) { + Mrl * m = c->mrl (); + if (m && m->opener == mrl) + return c; + } + return 0L; +} + +KDE_NO_CDTOR_EXPORT MediaTypeRuntime::MediaTypeRuntime (NodePtr e) + : Runtime (e) {} + +KDE_NO_CDTOR_EXPORT MediaTypeRuntime::~MediaTypeRuntime () { + killWGet (); +} + +/** + * re-implement for pending KIO::Job operations + */ +KDE_NO_EXPORT void KMPlayer::MediaTypeRuntime::reset () { + clear (); + postpone_lock = 0L; + Runtime::reset (); +} + +/** + * will request a repaint of attached region + */ +KDE_NO_EXPORT void MediaTypeRuntime::stopped () { + clipStop (); + document_postponed = 0L; + Node * e = element.ptr (); + if (e) { + for (NodePtr n = e->firstChild (); n; n = n->nextSibling ()) + if (n->unfinished ()) // finish child documents + n->finish (); + } + Runtime::stopped (); +} + +KDE_NO_EXPORT void MediaTypeRuntime::clipStart () { + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + SMIL::RegionBase *r =mt ? convertNode<SMIL::RegionBase>(mt->region_node):0L; + if (r && r->surface ()) + for (NodePtr n = mt->firstChild (); n; n = n->nextSibling ()) + if ((n->mrl () && n->mrl ()->opener.ptr () == mt) || + n->id == SMIL::id_node_smil || + n->id == RP::id_node_imfl) { + n->activate (); + break; + } +} + +KDE_NO_EXPORT void MediaTypeRuntime::clipStop () { + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (mt) { + mt->resetSurface (); + if (mt->external_tree && mt->external_tree->active ()) + mt->external_tree->deactivate (); + } +} + +KDE_NO_EXPORT void MediaTypeRuntime::postpone (bool) { +} + +KDE_NO_CDTOR_EXPORT AudioVideoData::AudioVideoData (NodePtr e) + : MediaTypeRuntime (e) {} + +KDE_NO_EXPORT bool AudioVideoData::isAudioVideo () { + return timingstate == timings_started; +} + +/** + * reimplement for request backend to play audio/video + */ +KDE_NO_EXPORT void AudioVideoData::started () { + if (element && !element->mrl ()->resolved) { + element->defer (); + return; + } + if (0 == durTime ().offset && dur_media == endTime ().durval) + durTime ().durval = dur_media; // duration of clip + MediaTypeRuntime::started (); +} + +static void setSmilLinkNode (NodePtr n, NodePtr link) { + // this works only because we can only play one at a time FIXME + SMIL::Smil * s = SMIL::Smil::findSmilNode (n.ptr ()); + if (s && (link || s->current_av_media_type == n)) // only reset ones own + s->current_av_media_type = link; +} + +KDE_NO_EXPORT void AudioVideoData::clipStart () { + NodePtr element_protect = element; // note element is weak + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + PlayListNotify * n = mt ? mt->document ()->notify_listener : 0L; + //kdDebug() << "AudioVideoData::clipStart " << mt->resolved << endl; + if (n && mt->region_node && !mt->external_tree && !mt->src.isEmpty()) { + setSmilLinkNode (element, element); + mt->repeat = repeat_count == dur_infinite ? 9998 : repeat_count; + repeat_count = 0; + n->requestPlayURL (mt); + document_postponed = mt->document()->connectTo(mt, event_postponed); + } + MediaTypeRuntime::clipStart (); +} + +KDE_NO_EXPORT void AudioVideoData::clipStop () { + if (durTime ().durval == dur_media) + durTime ().durval = dur_timer;//reset to make this finish + MediaTypeRuntime::clipStop (); + setSmilLinkNode (element, 0L); +} + +KDE_NO_EXPORT +bool AudioVideoData::parseParam(const TrieString &name, const QString &val) { + //kdDebug () << "AudioVideoData::parseParam " << name << "=" << val << endl; + if (name == StringPool::attr_src) { + NodePtr element_protect = element; // note element is weak + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (mt) { + if (!mt->resolved || mt->src != val) { + if (mt->external_tree) + mt->removeChild (mt->external_tree); + mt->src = val; + mt->resolved = mt->document ()->notify_listener->resolveURL (element); + } + if (timingstate == timings_started && mt->resolved) + clipStart (); + } + } else + return MediaTypeRuntime::parseParam (name, val); + return true; +} + +KDE_NO_EXPORT void AudioVideoData::postpone (bool b) { + kdDebug () << "AudioVideoData::postpone " << b << endl; + if (element->unfinished () && b) + element->setState (Node::state_deferred); + else if (element->state == Node::state_deferred && !b) + element->setState (Node::state_began); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT MouseListeners::MouseListeners () : + m_ActionListeners (new NodeRefList), + m_OutOfBoundsListeners (new NodeRefList), + m_InBoundsListeners (new NodeRefList) {} + +NodeRefListPtr MouseListeners::listeners (unsigned int eid) { + switch (eid) { + case event_activated: + return m_ActionListeners; + case event_inbounds: + return m_InBoundsListeners; + case event_outbounds: + return m_OutOfBoundsListeners; + } + return 0L; +} + +//----------------------------------------------------------------------------- + +static Element * fromScheduleGroup (NodePtr & d, const QString & tag) { + const char * ctag = tag.ascii (); + if (!strcmp (ctag, "par")) + return new SMIL::Par (d); + else if (!strcmp (ctag, "seq")) + return new SMIL::Seq (d); + else if (!strcmp (ctag, "excl")) + return new SMIL::Excl (d); + return 0L; +} + +static Element * fromParamGroup (NodePtr & d, const QString & tag) { + const char * ctag = tag.ascii (); + if (!strcmp (ctag, "param")) + return new SMIL::Param (d); + else if (!strcmp (ctag, "area") || !strcmp (ctag, "anchor")) + return new SMIL::Area (d, tag); + return 0L; +} + +static Element * fromAnimateGroup (NodePtr & d, const QString & tag) { + const char * ctag = tag.ascii (); + if (!strcmp (ctag, "set")) + return new SMIL::Set (d); + else if (!strcmp (ctag, "animate")) + return new SMIL::Animate (d); + else if (!strcmp (ctag, "animateMotion")) + return new SMIL::AnimateMotion (d); + return 0L; +} + +static Element * fromMediaContentGroup (NodePtr & d, const QString & tag) { + const char * taglatin = tag.latin1 (); + if (!strcmp (taglatin, "video") || !strcmp (taglatin, "audio")) + return new SMIL::AVMediaType (d, tag); + else if (!strcmp (taglatin, "img")) + return new SMIL::ImageMediaType (d); + else if (!strcmp (taglatin, "text")) + return new SMIL::TextMediaType (d); + else if (!strcmp (taglatin, "ref")) + return new SMIL::RefMediaType (d); + else if (!strcmp (taglatin, "brush")) + return new SMIL::Brush (d); + else if (!strcmp (taglatin, "a")) + return new SMIL::Anchor (d); + // animation, textstream + return 0L; +} + +static Element * fromContentControlGroup (NodePtr & d, const QString & tag) { + if (!strcmp (tag.latin1 (), "switch")) + return new SMIL::Switch (d); + return 0L; +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT NodePtr SMIL::Smil::childFromTag (const QString & tag) { + const char * ctag = tag.ascii (); + if (!strcmp (ctag, "body")) + return new SMIL::Body (m_doc); + else if (!strcmp (ctag, "head")) + return new SMIL::Head (m_doc); + return NodePtr (); +} + +KDE_NO_EXPORT void SMIL::Smil::activate () { + //kdDebug () << "Smil::activate" << endl; + current_av_media_type = NodePtr (); + resolved = true; + SMIL::Layout * layout = convertNode <SMIL::Layout> (layout_node); + if (layout && layout->region_surface) { + kdError() << "Layout already has a surface" << endl; + } + if (layout) + Element::activate (); + else + Element::deactivate(); // some unfortunate reset in parent doc +} + +KDE_NO_EXPORT void SMIL::Smil::deactivate () { + if (layout_node) + convertNode <SMIL::Layout> (layout_node)->repaint (); + if (layout_node) + convertNode <SMIL::Layout> (layout_node)->region_surface = NULL; + Mrl::getSurface(0L); + Mrl::deactivate (); +} + +KDE_NO_EXPORT bool SMIL::Smil::handleEvent (EventPtr event) { + return layout_node ? layout_node->handleEvent (event) : false; +} + +KDE_NO_EXPORT void SMIL::Smil::closed () { + NodePtr head; + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->id == id_node_head) { + head = e; + break; + } + if (!head) { + SMIL::Head * h = new SMIL::Head (m_doc); + insertBefore (h, firstChild ()); + h->setAuxiliaryNode (true); + h->closed (); + head = h; + } + for (NodePtr e = head->firstChild (); e; e = e->nextSibling ()) { + if (e->id == id_node_layout) { + layout_node = e; + } else if (e->id == id_node_title) { + QString str = e->innerText (); + pretty_name = str.left (str.find (QChar ('\n'))); + } else if (e->id == id_node_meta) { + Element * elm = convertNode <Element> (e); + const QString name = elm->getAttribute (StringPool::attr_name); + if (name == QString::fromLatin1 ("title")) + pretty_name = elm->getAttribute ("content"); + else if (name == QString::fromLatin1 ("base")) + src = elm->getAttribute ("content"); + } + } + if (!layout_node) { + kdError () << "no <root-layout>" << endl; + return; + } +} + +KDE_NO_EXPORT void SMIL::Smil::childDone (NodePtr child) { + if (unfinished ()) { + if (child->nextSibling ()) + child->nextSibling ()->activate (); + else { + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->active ()) + e->deactivate (); + finish (); + } + } +} + +KDE_NO_EXPORT Mrl * SMIL::Smil::linkNode () { + return current_av_media_type ? current_av_media_type->mrl () : this; +} + +KDE_NO_EXPORT bool SMIL::Smil::expose () const { + return !pretty_name.isEmpty () || //return false if no title and only one + previousSibling () || nextSibling (); +} + +KDE_NO_EXPORT void SMIL::Smil::accept (Visitor * v) { + if (active () && layout_node) + layout_node->accept( v ); +} + +void SMIL::Smil::jump (const QString & id) { + NodePtr n = document ()->getElementById (this, id, false); + if (n) { + if (n->unfinished ()) + kdDebug() << "Smil::jump node is unfinished " << id << endl; + else { + for (NodePtr p = n; p; p = p->parentNode ()) { + if (p->unfinished () && + p->id >= id_node_first_group && + p->id <= id_node_last_group) { + convertNode <GroupBase> (p)->setJumpNode (n); + break; + } + if (n->id == id_node_body || n->id == id_node_smil) { + kdError() << "Smil::jump node passed body for " <<id<< endl; + break; + } + } + } + } +} + +SMIL::Smil * SMIL::Smil::findSmilNode (Node * node) { + for (Node * e = node; e; e = e->parentNode ().ptr ()) + if (e->id == SMIL::id_node_smil) + return static_cast <SMIL::Smil *> (e); + return 0L; +} + +//----------------------------------------------------------------------------- + +static void headChildDone (NodePtr node, NodePtr child) { + if (node->unfinished ()) { + if (child->nextSibling ()) + child->nextSibling ()->activate (); + else + node->finish (); // we're done + } +} + +KDE_NO_EXPORT NodePtr SMIL::Head::childFromTag (const QString & tag) { + const char * ctag = tag.ascii (); + if (!strcmp (ctag, "layout")) + return new SMIL::Layout (m_doc); + else if (!strcmp (ctag, "title")) + return new DarkNode (m_doc, tag, id_node_title); + else if (!strcmp (ctag, "meta")) + return new DarkNode (m_doc, tag, id_node_meta); + else if (!strcmp (ctag, "transition")) + return new SMIL::Transition (m_doc); + return NodePtr (); +} + +KDE_NO_EXPORT bool SMIL::Head::expose () const { + return false; +} + +KDE_NO_EXPORT void SMIL::Head::closed () { + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->id == id_node_layout) + return; + SMIL::Layout * layout = new SMIL::Layout (m_doc); + appendChild (layout); + layout->setAuxiliaryNode (true); + layout->closed (); // add root-layout and a region +} + +KDE_NO_EXPORT void SMIL::Head::childDone (NodePtr child) { + headChildDone (this, child); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::Layout::Layout (NodePtr & d) + : RegionBase (d, id_node_layout) {} + +KDE_NO_EXPORT NodePtr SMIL::Layout::childFromTag (const QString & tag) { + const char * ctag = tag.ascii (); + if (!strcmp (ctag, "root-layout")) { + NodePtr e = new SMIL::RootLayout (m_doc); + rootLayout = e; + return e; + } else if (!strcmp (ctag, "region")) + return new SMIL::Region (m_doc); + else if (!strcmp (ctag, "regPoint")) + return new SMIL::RegPoint (m_doc); + return NodePtr (); +} + +KDE_NO_EXPORT void SMIL::Layout::closed () { + SMIL::RegionBase * rl = convertNode <SMIL::RootLayout> (rootLayout); + bool has_root (rl); + if (!has_root) { // just add one if none there + rl = new SMIL::RootLayout (m_doc); + NodePtr sr = rl; // protect against destruction + rl->setAuxiliaryNode (true); + rootLayout = rl; + int w_root =0, h_root = 0, reg_count = 0; + for (NodePtr n = firstChild (); n; n = n->nextSibling ()) { + if (n->id == id_node_region) { + SMIL::Region * rb =convertNode <SMIL::Region> (n); + rb->init (); + rb->calculateBounds (0, 0); + if (int (rb->x + rb->w) > w_root) + w_root = rb->x + rb->w; + if (int (rb->y + rb->h) > h_root) + h_root = rb->y + rb->h; + reg_count++; + } + } + if (!reg_count) { + w_root = 320; h_root = 240; // have something to start with + SMIL::Region * r = new SMIL::Region (m_doc); + appendChild (r); + r->setAuxiliaryNode (true); + } + rl->setAttribute(StringPool::attr_width, QString::number(w_root)); + rl->setAttribute(StringPool::attr_height,QString::number(h_root)); + insertBefore (sr, firstChild ()); + } else { + if (childNodes ()->length () < 2) { // only a root-layout + SMIL::Region * r = new SMIL::Region (m_doc); + appendChild (r); + r->setAuxiliaryNode (true); + } + Smil *s = Smil::findSmilNode (this); + if (s) { + s->width = rl->getAttribute(StringPool::attr_width).toDouble (); + s->height = rl->getAttribute(StringPool::attr_height).toDouble(); + } + } +} + +KDE_NO_EXPORT void SMIL::Layout::activate () { + //kdDebug () << "SMIL::Layout::activate" << endl; + RegionBase::activate (); + if (surface ()) { + updateDimensions (); + repaint (); + } + finish (); // proceed and allow 'head' to finish +} + +KDE_NO_EXPORT void SMIL::Layout::updateDimensions () { + RegionBase * rb = static_cast <RegionBase *> (rootLayout.ptr ()); + x = y = 0; + w = rb->sizes.width.size (); + h = rb->sizes.height.size (); + //kdDebug () << "Layout::updateDimensions " << w << "," << h <<endl; + SMIL::RegionBase::updateDimensions (); +} + +KDE_NO_EXPORT Surface *SMIL::Layout::surface () { + if (!region_surface) { + SMIL::Smil * s = Smil::findSmilNode (this); + if (s) { + SMIL::RegionBase *rl = convertNode <SMIL::RootLayout> (rootLayout); + region_surface = s->getSurface (s); + w = s->width; + h = s->height; + if (region_surface) { + SRect rect = region_surface->bounds; + if (rl && auxiliaryNode ()) { + w = rect.width (); + h = rect.height (); + rl->setAttribute (StringPool::attr_width, QString::number ((int)w)); + rl->setAttribute (StringPool::attr_height, QString::number ((int)h)); + rl->setParam (StringPool::attr_width, QString::number((int)w)); + rl->setParam (StringPool::attr_height,QString::number((int)h)); + } else if (region_surface && w > 0 && h > 0) { + updateDimensions (); + } + //kdDebug() << "Layout::surface bounds " << rect.width () << "x" << rect.height () << " w:" << w << " h:" << h << " xs:" << region_surface->xscale << " ys:" << region_surface->yscale << endl; + } + } + } + return region_surface.ptr (); +} + +KDE_NO_EXPORT void SMIL::Layout::accept (Visitor * v) { + v->visit (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::RegionBase::RegionBase (NodePtr & d, short id) + : Element (d, id), x (0), y (0), w (0), h (0), + z_order (1), background_color (0) + {} + +KDE_NO_CDTOR_EXPORT SMIL::RegionBase::~RegionBase () { + if (region_surface) + region_surface->remove (); +} + +KDE_NO_EXPORT void SMIL::RegionBase::activate () { + show_background = ShowAlways; + init (); + setState (state_activated); + for (NodePtr r = firstChild (); r; r = r->nextSibling ()) + if (r->id == id_node_region || r->id == id_node_root_layout) + r->activate (); +} + +KDE_NO_EXPORT void SMIL::RegionBase::childDone (NodePtr child) { + headChildDone (this, child); +} + +KDE_NO_EXPORT void SMIL::RegionBase::deactivate () { + background_color = 0; + background_image.truncate (0); + if (region_surface) + region_surface->background_color = 0; + cached_img.setUrl (QString ()); + postpone_lock = NULL; + killWGet (); + sizes.resetSizes (); + Element::deactivate (); +} + +KDE_NO_EXPORT void SMIL::RegionBase::remoteReady (QByteArray & data) { + QImage *pix = new QImage (data); + if (!pix->isNull ()) { + cached_img.data->image = pix; + if (region_surface) + region_surface->remove (); // FIXME: only surface + } else { + delete pix; + } + postpone_lock = 0L; +} + +KDE_NO_EXPORT void SMIL::RegionBase::repaint () { + if (surface ()) + region_surface->repaint (SRect (0, 0, w, h)); +} + +KDE_NO_EXPORT void SMIL::RegionBase::repaint (const SRect & rect) { + if (surface ()) + region_surface->repaint (SRect (0, 0, w, h).intersect (rect)); +} + +KDE_NO_EXPORT void SMIL::RegionBase::updateDimensions () { + if (surface () && active ()) + for (NodePtr r = firstChild (); r; r = r->nextSibling ()) + if (r->id == id_node_region) { + SMIL::Region * cr = static_cast <SMIL::Region *> (r.ptr ()); + cr->calculateBounds (w, h); + cr->updateDimensions (); + } +} + +KDE_NO_EXPORT void SMIL::RegionBase::boundsUpdate () { + // if there is a region_surface and it's moved, do a limit repaint + NodePtr p = parentNode (); + if (p && (p->id==SMIL::id_node_region || p->id==SMIL::id_node_layout) && + region_surface) { + RegionBase *pr = convertNode <SMIL::RegionBase> (p); + SRect old_bounds = region_surface->bounds; + w = 0; h = 0; + sizes.calcSizes (this, pr->w, pr->h, x, y, w, h); + region_surface->bounds = SRect (x, y, w, h); + pr->repaint (region_surface->bounds.unite (old_bounds)); + } +} + +KDE_NO_EXPORT Surface *SMIL::RegionBase::surface () { + if (!region_surface) { + Node *n = parentNode ().ptr (); + if (n && + (SMIL::id_node_region == n->id || + SMIL::id_node_layout == n->id)) { + Surface *ps = static_cast <SMIL::Region *> (n)->surface (); + if (ps) { + region_surface = ps->createSurface (this, SRect (x, y, w, h)); + region_surface->background_color = background_color; + } + } + } + return region_surface.ptr (); +} + +KDE_NO_EXPORT +void SMIL::RegionBase::parseParam (const TrieString & name, const QString & val) { + //kdDebug () << "RegionBase::parseParam " << getAttribute ("id") << " " << name << "=" << val << " active:" << active() << endl; + bool need_repaint = false; + SRect rect = SRect (x, y, w, h); + bool dim_changed; + if (name == "background-color" || name == "backgroundColor") { + if (val.isEmpty ()) + background_color = 0; + else + background_color = 0xff000000 | QColor (val).rgb (); + if (region_surface || (active () && surface ())) + region_surface->background_color = background_color; + need_repaint = true; + } else if (name == "z-index") { + z_order = val.toInt (); + need_repaint = true; + } else if (sizes.setSizeParam (name, val, dim_changed)) { + if (active ()) { + if (region_surface) { + if (dim_changed) { + region_surface->remove (); + } else { + boundsUpdate (); + return; // smart update of old bounds to new moved one + } + } + NodePtr p = parentNode (); + if (p &&(p->id==SMIL::id_node_region ||p->id==SMIL::id_node_layout)) + convertNode <SMIL::RegionBase> (p)->updateDimensions (); + rect = rect.unite (SRect (x, y, w, h)); + need_repaint = true; + } + } else if (name == "showBackground") { + if (val == "whenActive") + show_background = ShowWhenActive; + else + show_background = ShowAlways; + need_repaint = true; + } else if (name == "backgroundImage") { + background_image = val; + Smil * s = SMIL::Smil::findSmilNode (this); + if (s) { + killWGet (); + need_repaint = !cached_img.isEmpty (); + Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL; + QString url = mrl ? KURL (mrl->absolutePath (), val).url () : val; + cached_img.setUrl (url); + if (cached_img.isEmpty ()) { + postpone_lock = document ()->postpone (); + wget (url); + } else { + need_repaint = true; + } + } + } + if (need_repaint && active () && surface() && region_surface->parentNode ()) + region_surface->parentNode ()->repaint (rect); + Element::parseParam (name, val); +} + +KDE_NO_CDTOR_EXPORT SMIL::Region::Region (NodePtr & d) + : RegionBase (d, id_node_region), + has_mouse (false), + m_AttachedMediaTypes (new NodeRefList) {} + +KDE_NO_EXPORT NodePtr SMIL::Region::childFromTag (const QString & tag) { + if (!strcmp (tag.latin1 (), "region")) + return new SMIL::Region (m_doc); + return NodePtr (); +} + +/** + * calculates dimensions of this regions with _w and _h as width and height + * of parent Region (representing 100%) + */ +KDE_NO_EXPORT +void SMIL::Region::calculateBounds (Single pw, Single ph) { + Single x1 (x), y1 (y), w1 (w), h1 (h); + sizes.calcSizes (this, pw, ph, x, y, w, h); + if (surface ()) + region_surface->bounds = SRect (x, y, w, h); + //kdDebug () << "Region::calculateBounds parent:" << pw << "x" << ph << " this:" << x << "," << y << " " << w << "x" << h << endl; +} + +NodeRefListPtr SMIL::Region::listeners (unsigned int eid) { + NodeRefListPtr l = mouse_listeners.listeners (eid); + if (l) + return l; + switch (eid) { + case mediatype_attached: + return m_AttachedMediaTypes; + } + return RegionBase::listeners (eid); +} + +KDE_NO_EXPORT void SMIL::Region::accept (Visitor * v) { + v->visit (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT +void SMIL::RegPoint::parseParam (const TrieString & p, const QString & v) { + bool b; + sizes.setSizeParam (p, v, b); // TODO: if dynamic, make sure to repaint + Element::parseParam (p, v); +} + +//----------------------------------------------------------------------------- + +static struct TransTypeInfo { + const char *name; + SMIL::Transition::TransType type; + short sub_types; + SMIL::Transition::TransSubType sub_type[8]; +} transition_type_info[] = { +#include "transitions.txt" +}; + +static struct SubTransTypeInfo { + const char *name; + SMIL::Transition::TransSubType sub_type; +} sub_transition_type_info[] = { +#include "subtrans.txt" +}; + +static TransTypeInfo *transInfoFromString (const char *t) { + // TODO binary search + for (int i = 0; transition_type_info[i].name; ++i) + if (!strcmp (t, transition_type_info[i].name)) + return transition_type_info + i; + return NULL; +} + +static +SMIL::Transition::TransSubType subTransInfoFromString (const char *s) { + for (int i = 0; sub_transition_type_info[i].name; ++i) + if (!strcmp (s, sub_transition_type_info[i].name)) + return sub_transition_type_info[i].sub_type; + return SMIL::Transition::SubTransTypeNone; +} + +KDE_NO_CDTOR_EXPORT SMIL::Transition::Transition (NodePtr & d) + : Element (d, id_node_transition), + type_info (NULL), direction (dir_forward), dur (10), fade_color (0) {} + +KDE_NO_EXPORT void SMIL::Transition::activate () { + type = TransTypeNone; + sub_type = SubTransTypeNone; + start_progress = 0.0; + end_progress = 1.0; + type_info = NULL; + init (); + Element::activate (); +} + +KDE_NO_EXPORT +void SMIL::Transition::parseParam (const TrieString & para, const QString & val) { + if (para == StringPool::attr_type) { + type_info = transInfoFromString (val.ascii ()); + if (type_info) { + type = type_info->type; + if (SubTransTypeNone != sub_type) { + for (int i = 0; i < type_info->sub_types; ++i) + if (type_info->sub_type[i] == sub_type) + return; + } + if (type_info->sub_types > 0) + sub_type = type_info->sub_type[0]; + } + } else if (para == StringPool::attr_dur) { + parseTime (val, dur); + } else if (para == "subtype") { + sub_type = subTransInfoFromString (val.ascii ()); + if (type_info) { + if (SubTransTypeNone != sub_type) { + for (int i = 0; i < type_info->sub_types; ++i) + if (type_info->sub_type[i] == sub_type) + return; + } + if (type_info->sub_types > 0) + sub_type = type_info->sub_type[0]; + } + } else if (para == "fadeColor") { + fade_color = QColor (getAttribute (val)).rgb (); + } else if (para == "direction") { + direction = val == "reverse" ? dir_reverse : dir_forward; + } else if (para == "startProgress") { + start_progress = val.toDouble(); + if (start_progress < 0.0) + start_progress = 0.0; + else if (start_progress > 1.0) + start_progress = 1.0; + } else if (para == "endProgress") { + end_progress = val.toDouble(); + if (end_progress < start_progress) + end_progress = start_progress; + else if (end_progress > 1.0) + end_progress = 1.0; + } else { + Element::parseParam (para, val); + } +} + +KDE_NO_EXPORT bool SMIL::Transition::supported () { + switch (type) { + case Fade: + case BarWipe: + case BowTieWipe: + case PushWipe: + case IrisWipe: + case ClockWipe: + case EllipseWipe: + return true; + default: + return false; + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::TimedMrl::TimedMrl (NodePtr & d, short id) + : Mrl (d, id), + fill_active (fill_auto), + m_StartListeners (new NodeRefList), + m_StartedListeners (new NodeRefList), + m_StoppedListeners (new NodeRefList), + m_runtime (0L) {} + +KDE_NO_CDTOR_EXPORT SMIL::TimedMrl::~TimedMrl () { + delete m_runtime; +} + +KDE_NO_EXPORT void SMIL::TimedMrl::closed () { + pretty_name = getAttribute (StringPool::attr_title); + Mrl::closed (); +} + +KDE_NO_EXPORT void SMIL::TimedMrl::init () { + runtime ()->reset (); + begin_time = finish_time = 0; + fill = fill_default; + fill_def = fill_inherit; + fill_active = getDefaultFill (this); + Mrl::init (); +} + +KDE_NO_EXPORT void SMIL::TimedMrl::activate () { + //kdDebug () << "SMIL::TimedMrl(" << nodeName() << ")::activate" << endl; + Runtime * rt = runtime (); + init (); + setState (state_activated); + if (rt == m_runtime) // Runtime might already be dead + rt->begin (); + else + deactivate (); +} + +KDE_NO_EXPORT void SMIL::TimedMrl::begin () { + begin_time = document ()->last_event_time; + Element::begin (); + runtime ()->propagateStop (false); //see whether this node has a livetime or not +} + +KDE_NO_EXPORT void SMIL::TimedMrl::deactivate () { + //kdDebug () << "SMIL::TimedMrl(" << nodeName() << ")::deactivate" << endl; + if (unfinished ()) + finish (); + if (m_runtime) { + m_runtime->reset (); + delete m_runtime; + m_runtime = 0L; + } + Mrl::deactivate (); +} + +KDE_NO_EXPORT void SMIL::TimedMrl::finish () { + if (m_runtime && + (m_runtime->state () == Runtime::timings_started || + m_runtime->state () == Runtime::timings_began)) { + runtime ()->propagateStop (true); // reschedule through Runtime::stopped + } else { + finish_time = document ()->last_event_time; + Mrl::finish (); + propagateEvent (new Event (event_stopped)); + } +} + +KDE_NO_EXPORT void SMIL::TimedMrl::reset () { + //kdDebug () << "SMIL::TimedMrl::reset " << endl; + Mrl::reset (); + delete m_runtime; + m_runtime = 0L; +} + +KDE_NO_EXPORT void SMIL::TimedMrl::childBegan (NodePtr) { + if (state != state_began) + begin (); +} + +/* + * Re-implement, but keeping sequential behaviour. + * Bail out if Runtime is running. In case of dur_media, give Runtime + * a hand with calling propagateStop(true) + */ +KDE_NO_EXPORT void SMIL::TimedMrl::childDone (NodePtr c) { + if (!active ()) + return; // forced reset + if (c->nextSibling ()) + c->nextSibling ()->activate (); + else { // check if Runtime still running + Runtime * tr = runtime (); + if (tr->state () < Runtime::timings_stopped) { + if (tr->state () == Runtime::timings_started) + tr->propagateStop (false); + return; // still running, wait for runtime to finish + } + finish (); + } +} + +KDE_NO_EXPORT NodeRefListPtr SMIL::TimedMrl::listeners (unsigned int id) { + if (id == event_stopped) + return m_StoppedListeners; + else if (id == event_started) + return m_StartedListeners; + else if (id == event_to_be_started) + return m_StartListeners; + kdWarning () << "unknown event requested" << endl; + return NodeRefListPtr (); +} + +KDE_NO_EXPORT bool SMIL::TimedMrl::handleEvent (EventPtr event) { + int id = event->id (); + switch (id) { + case event_timer: { + TimerEvent * te = static_cast <TimerEvent *> (event.ptr ()); + if (te && te->timer_info) { + if (te->timer_info->event_id == started_timer_id) + runtime ()->started (); + else if (te->timer_info->event_id == stopped_timer_id) + runtime ()->stopped (); + else if (te->timer_info->event_id == start_timer_id) + runtime ()->propagateStart (); + else if (te->timer_info->event_id == dur_timer_id) + runtime ()->propagateStop (true); + else + kdWarning () << "unhandled timer event" << endl; + } + break; + } + default: + if (m_runtime) + m_runtime->processEvent (id); + } + return true; +} + +KDE_NO_EXPORT Runtime * SMIL::TimedMrl::getNewRuntime () { + return new Runtime (this); +} + +KDE_NO_EXPORT +void SMIL::TimedMrl::parseParam (const TrieString ¶, const QString &value) { + if (para.startsWith (StringPool::attr_fill)) { + Fill * f = &fill; + if (para != StringPool::attr_fill) { + f = &fill_def; + *f = fill_inherit; + } else + *f = fill_default; + fill_active = fill_auto; + if (value == "freeze") + *f = fill_freeze; + else if (value == "hold") + *f = fill_hold; + else if (value == "auto") + *f = fill_auto; + else if (value == "remove") + *f = fill_remove; + else if (value == "transition") + *f = fill_transition; + if (fill == fill_default) { + if (fill_def == fill_inherit) + fill_active = getDefaultFill (this); + else + fill_active = fill_def; + } else + fill_active = fill; + } else if (!runtime ()->parseParam (para, value)) { + if (para == StringPool::attr_src) //block Mrl src parsing for now + kdDebug() << "parseParam src on " << nodeName() << endl; + else + Mrl::parseParam (para, value); + } +} + +KDE_NO_EXPORT +Runtime::DurationItem * SMIL::TimedMrl::getDuration (NodePtr n) { + if (!isTimedMrl (n) || !n->active ()) + return 0L; + TimedMrl * tm = convertNode <SMIL::TimedMrl> (n); + return &tm->runtime ()->durations [Runtime::duration_time]; +} + +KDE_NO_EXPORT bool SMIL::TimedMrl::keepContent (Node *n) { + if (isTimedMrl (n)) { + TimedMrl * tm = convertNode <SMIL::TimedMrl> (n); + if (tm->runtime ()->timingstate == Runtime::timings_started) + return true; + Node *p = n->parentNode (); + Node *np = tm; + while (p && id_node_body != p->id && !isTimedMrl (p)) { + np = p; + p = p->parentNode ().ptr (); // skip anchors + } + if (tm->m_runtime && p && p->active ()) { + if (tm->runtime ()->timingstate == Runtime::timings_stopped) + switch (tm->fill_active) { + case fill_hold: // keep while parent active + return true; + case fill_freeze: // keep in parent duration + if (p->unfinished() && + (p->id == SMIL::id_node_par || + p->id == SMIL::id_node_excl || + p->id == SMIL::id_node_switch || + p->lastChild().ptr () == np)) + return true; + // else fall through + case fill_default: // as freeze when no duration is set + case fill_auto: // or when parent finished w/o duration + return keepContent (p) && + (p->id == SMIL::id_node_par || + p->id == SMIL::id_node_excl || + p->id == SMIL::id_node_switch || + p->lastChild().ptr () == np) && + tm->runtime ()->durTime ().durval == Runtime::dur_timer && + !tm->runtime ()->durTime ().offset; + default: + break; + } + } + return false; + } + return true; +} + +KDE_NO_EXPORT SMIL::TimedMrl::Fill SMIL::TimedMrl::getDefaultFill (NodePtr n) { + for (NodePtr p = n->parentNode (); p; p = p->parentNode ()) + if (isTimedMrl (p)) { + SMIL::TimedMrl * tm = convertNode<SMIL::TimedMrl>(p); + if (tm->fill_def != fill_inherit) + return tm->fill_def; + else if (tm->fill == fill_default) + return tm->fill_active; // assume parent figured out this + } else if (p->id == SMIL::id_node_smil) + break; + return fill_auto; +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT NodePtr SMIL::GroupBase::childFromTag (const QString & tag) { + Element * elm = fromScheduleGroup (m_doc, tag); + if (!elm) elm = fromMediaContentGroup (m_doc, tag); + if (!elm) elm = fromContentControlGroup (m_doc, tag); + if (!elm) elm = fromAnimateGroup (m_doc, tag); + if (elm) + return elm; + return NULL; +} + +KDE_NO_EXPORT void SMIL::GroupBase::finish () { + setState (state_finished); // avoid recurstion through childDone + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (keepContent (e)) { + if (e->unfinished ()) + e->finish (); + } else if (e->active ()) + e->deactivate (); + TimedMrl::finish (); +} + +KDE_NO_EXPORT void SMIL::GroupBase::deactivate () { + setState (state_deactivated); // avoid recurstion through childDone + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->active ()) + e->deactivate (); + TimedMrl::deactivate (); +} + +KDE_NO_EXPORT void SMIL::GroupBase::setJumpNode (NodePtr n) { + NodePtr child = n; + if (state > state_init) { + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->active ()) + c->reset (); + for (NodePtr c = n->parentNode (); c; c = c->parentNode ()) { + if (c.ptr () == this || c->id == id_node_body) + break; + if (c->id >= id_node_first_group && c->id <= id_node_last_group) + convertNode <GroupBase> (c)->jump_node = child; + child = c; + } + } + jump_node = child; + state = state_activated; + init (); + runtime()->beginAndStart (); // undefer through begin() +} + +//----------------------------------------------------------------------------- + +// SMIL::Body was here + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void SMIL::Par::begin () { + jump_node = 0L; // TODO: adjust timings + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + e->activate (); + GroupBase::begin (); +} + +KDE_NO_EXPORT void SMIL::Par::reset () { + GroupBase::reset (); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + e->reset (); +} + +KDE_NO_EXPORT void SMIL::Par::childDone (NodePtr) { + if (unfinished ()) { + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e->unfinished ()) + return; // not all finished + } + Runtime * tr = runtime (); + if (tr->state () == Runtime::timings_started) { + Runtime::Duration dv = tr->durTime ().durval; + if ((dv == Runtime::dur_timer && !tr->durTime ().offset) + || dv == Runtime::dur_media) + tr->propagateStop (false); + return; // still running, wait for runtime to finish + } + finish (); // we're done + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void SMIL::Seq::begin () { + if (jump_node) { + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c == jump_node) { + jump_node = 0L; + c->activate (); + break; + } else { + c->state = state_activated; // TODO: .. + if (c->isElementNode ()) + convertNode <Element> (c)->init (); + c->state = state_finished; // TODO: .. + } + } else if (firstChild ()) + firstChild ()->activate (); + GroupBase::begin (); +} + +KDE_NO_EXPORT void SMIL::Seq::childDone (NodePtr child) { + if (unfinished ()) { + if (state != state_deferred) { + if (!keepContent (child) && child->active ()) + child->deactivate (); + if (child->nextSibling ()) + child->nextSibling ()->activate (); + else + finish (); + } else if (jump_node) + finish (); + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void SMIL::Excl::begin () { + //kdDebug () << "SMIL::Excl::begin" << endl; + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + e->activate (); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (isTimedMrl (e)) { + SMIL::TimedMrl * tm = static_cast <SMIL::TimedMrl *> (e.ptr ()); + if (tm) { // make aboutToStart connection with TimedMrl children + ConnectionPtr c = tm->connectTo (this, event_to_be_started); + started_event_list.append (new ConnectionStoreItem (c)); + } + } + GroupBase::begin (); +} + +KDE_NO_EXPORT void SMIL::Excl::deactivate () { + started_event_list.clear (); // auto disconnect on destruction of data items + GroupBase::deactivate (); +} + +KDE_NO_EXPORT void SMIL::Excl::childDone (NodePtr /*child*/) { + // first check if somenode has taken over + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (isTimedMrl (e)) { + Runtime *tr = convertNode <SMIL::TimedMrl> (e)->runtime(); + if (tr->state () == Runtime::timings_started) + return; + } + // now finish unless 'dur="indefinite/some event/.."' + Runtime * tr = runtime (); + if (tr->state () == Runtime::timings_started) + tr->propagateStop (false); // still running, wait for runtime to finish + else + finish (); // we're done +} + +KDE_NO_EXPORT bool SMIL::Excl::handleEvent (EventPtr event) { + if (event->id () == event_to_be_started) { + ToBeStartedEvent * se = static_cast <ToBeStartedEvent *> (event.ptr ()); + //kdDebug () << "Excl::handleEvent " << se->node->nodeName()<<endl; + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e == se->node) // stop all _other_ child elements + continue; + if (!isTimedMrl (e)) + continue; // definitely a stowaway + convertNode<SMIL::TimedMrl>(e)->runtime()->propagateStop(true); + } + return true; + } else + return TimedMrl::handleEvent (event); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void SMIL::Switch::begin () { + //kdDebug () << "SMIL::Switch::activate" << endl; + PlayListNotify * n = document()->notify_listener; + int pref = 0, max = 0x7fffffff, currate = 0; + if (n) + n->bitRates (pref, max); + if (firstChild ()) { + NodePtr fallback; + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->isElementNode ()) { + Element *elm = convertNode <Element> (e); + QString lang = elm->getAttribute ("systemLanguage"); + if (!lang.isEmpty ()) { + lang = lang.replace (QChar ('-'), QChar ('_')); + char *clang = getenv ("LANG"); + if (!clang) { + if (!fallback) + fallback = e; + } else if (QString (clang).lower ().startsWith (lang)) { + chosenOne = e; + } else if (!fallback) { + fallback = e->nextSibling (); + } + } + if (e->id == id_node_audio_video) { + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (e); + if (!chosenOne) { + chosenOne = e; + currate = mt->bitrate; + } else if (int (mt->bitrate) <= max) { + int delta1 = pref > currate ? pref-currate : currate-pref; + int delta2 = pref > int (mt->bitrate) ? pref-mt->bitrate : mt->bitrate-pref; + if (delta2 < delta1) { + chosenOne = e; + currate = mt->bitrate; + } + } + } else if (!fallback && e->isPlayable ()) + fallback = e; + } + if (!chosenOne) + chosenOne = (fallback ? fallback : firstChild ()); + chosenOne->activate (); + } + GroupBase::begin (); +} + +KDE_NO_EXPORT void SMIL::Switch::deactivate () { + Element::deactivate (); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->active ()) { + e->deactivate (); + break; // deactivate only the one running + } +} + +KDE_NO_EXPORT void SMIL::Switch::reset () { + Element::reset (); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e->state != state_init) + e->reset (); + } +} + +KDE_NO_EXPORT void SMIL::Switch::childDone (NodePtr child) { + if (child->state == state_finished) + child->deactivate (); + //kdDebug () << "SMIL::Switch::childDone" << endl; + finish (); // only one child can run +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::LinkingBase::LinkingBase (NodePtr & d, short id) + : Element(d, id), show (show_replace) {} + +KDE_NO_EXPORT void SMIL::LinkingBase::deactivate () { + mediatype_activated = 0L; + mediatype_attach = 0L; + Element::deactivate (); +} + +KDE_NO_EXPORT +void SMIL::LinkingBase::parseParam(const TrieString ¶, const QString &val) { + if (para == StringPool::attr_href) { + href = val; + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::Anchor::Anchor (NodePtr & d) + : LinkingBase (d, id_node_anchor) {} + +KDE_NO_EXPORT void SMIL::Anchor::activate () { + init (); + for (NodePtr c = firstChild(); c; c = c->nextSibling ()) + if (c->id >=id_node_first_mediatype && c->id <=id_node_last_mediatype) { + mediatype_activated = c->connectTo (this, event_activated); + mediatype_attach = c->connectTo (this, mediatype_attached); + break; + } + Element::activate (); +} + +KDE_NO_EXPORT void SMIL::Anchor::childDone (NodePtr child) { + if (unfinished ()) { + if (child->nextSibling ()) + child->nextSibling ()->activate (); + else + finish (); + } +} + +NodePtr SMIL::Anchor::childFromTag (const QString & tag) { + return fromMediaContentGroup (m_doc, tag); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::Area::Area (NodePtr & d, const QString & t) + : LinkingBase (d, id_node_area), coords (0L), nr_coords (0), tag (t) {} + +KDE_NO_CDTOR_EXPORT SMIL::Area::~Area () { + delete [] coords; +} + +KDE_NO_EXPORT void SMIL::Area::activate () { + init (); + if (parentNode () && + parentNode ()->id >= id_node_first_mediatype && + parentNode ()->id <= id_node_last_mediatype) { + mediatype_activated = parentNode ()->connectTo (this, event_activated); + mediatype_attach = parentNode ()->connectTo (this, mediatype_attached); + } + Element::activate (); +} + +KDE_NO_EXPORT +void SMIL::Area::parseParam (const TrieString & para, const QString & val) { + if (para == "coords") { + delete [] coords; + QStringList clist = QStringList::split (QString (","), val); + nr_coords = clist.count (); + coords = new SizeType [nr_coords]; + for (int i = 0; i < nr_coords; ++i) + coords[i] = clist[i]; + } else + LinkingBase::parseParam (para, val); +} + +KDE_NO_EXPORT NodeRefListPtr SMIL::Area::listeners (unsigned int id) { + NodeRefListPtr l = mouse_listeners.listeners (id); + if (l) + return l; + return Element::listeners (id); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::MediaType::MediaType (NodePtr &d, const QString &t, short id) + : TimedMrl (d, id), m_type (t), bitrate (0), trans_step (0), trans_steps (0), + sensitivity (sens_opaque), trans_out_active (false), + m_MediaAttached (new NodeRefList) { + view_mode = Mrl::WindowMode; +} + +KDE_NO_EXPORT NodePtr SMIL::MediaType::childFromTag (const QString & tag) { + Element * elm = fromContentControlGroup (m_doc, tag); + if (!elm) elm = fromParamGroup (m_doc, tag); + if (!elm) elm = fromAnimateGroup (m_doc, tag); + if (elm) + return elm; + return 0L; +} + +KDE_NO_EXPORT void SMIL::MediaType::closed () { + external_tree = findExternalTree (this); + Mrl *mrl = external_tree ? external_tree->mrl () : NULL; + if (mrl) { + width = mrl->width; + height = mrl->height; + } + TimedMrl::closed (); +} + +KDE_NO_EXPORT +void SMIL::MediaType::parseParam (const TrieString ¶, const QString & val) { + bool update_surface = true; + if (para == "fit") { + const char * cval = val.ascii (); + if (!cval) + fit = fit_hidden; + else if (!strcmp (cval, "fill")) + fit = fit_fill; + else if (!strcmp (cval, "hidden")) + fit = fit_hidden; + else if (!strcmp (cval, "meet")) + fit = fit_meet; + else if (!strcmp (cval, "scroll")) + fit = fit_scroll; + else if (!strcmp (cval, "slice")) + fit = fit_slice; + else + fit = fit_hidden; + } else if (para == "rn:mediaOpacity") { + opacity = (int) SizeType (val).size (100); + } else if (para == "system-bitrate") { + bitrate = val.toInt (); + } else if (para == StringPool::attr_type) { + mimetype = val; + } else if (para == "transIn") { + trans_in = findTransition (this, val); + if (!trans_in) + kdWarning() << "Transition " << val << " not found in head" << endl; + } else if (para == "transOut") { + trans_out = findTransition (this, val); + if (!trans_out) + kdWarning() << "Transition " << val << " not found in head" << endl; + } else if (para == "sensitivity") { + if (val == "transparent") + sensitivity = sens_transparent; + //else if (val == "percentage") // TODO + // sensitivity = sens_percentage; + else + sensitivity = sens_opaque; + } else if (sizes.setSizeParam (para, val, update_surface)) { + if (!update_surface && fit_hidden == fit && + sub_surface +#ifdef HAVE_CAIRO + && sub_surface->surface +#endif + ) { + boundsUpdate (); + return; // preserved surface by recalculationg sub_surface top-left + } + } else { + TimedMrl::parseParam (para, val); + } + if (sub_surface) + sub_surface->repaint (); + resetSurface (); + if (surface ()) + sub_surface->repaint (); +} + +KDE_NO_EXPORT void SMIL::MediaType::boundsUpdate () { + SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node); + if (rb && sub_surface) { + SRect new_bounds = calculateBounds (); + SRect repaint_rect = sub_surface->bounds.unite (new_bounds); + sub_surface->bounds = new_bounds; + rb->repaint (repaint_rect); + } +} + +KDE_NO_EXPORT void SMIL::MediaType::activate () { + trans_out_active = false; + fit = fit_hidden; + opacity = 100; + init (); // sets all attributes + setState (state_activated); + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c != external_tree) { + // activate param/set/animate.. children + c->activate (); + break; // childDone will handle next siblings + } + runtime ()->begin (); +} + +KDE_NO_EXPORT void SMIL::MediaType::deactivate () { + region_paint = 0L; + region_mouse_enter = 0L; + region_mouse_leave = 0L; + region_mouse_click = 0L; + region_attach = 0L; + trans_step = trans_steps = 0; + if (region_node) + convertNode <SMIL::RegionBase> (region_node)->repaint (); + if (trans_timer) + document ()->cancelTimer (trans_timer); + if (trans_out_timer) + document ()->cancelTimer (trans_out_timer); + TimedMrl::deactivate (); // keep region for runtime rest + region_node = 0L; +} + +KDE_NO_EXPORT void SMIL::MediaType::begin () { + SMIL::Smil * s = Smil::findSmilNode (parentNode ().ptr ()); + SMIL::Region * r = s ? + findRegion (s->layout_node, param (StringPool::attr_region)) : 0L; + MediaTypeRuntime *tr = static_cast<MediaTypeRuntime*>(runtime ()); + if (trans_timer) // eg transOut and we're repeating + document ()->cancelTimer (trans_timer); + if (r) { + region_node = r; + region_mouse_enter = r->connectTo (this, event_inbounds); + region_mouse_leave = r->connectTo (this, event_outbounds); + region_mouse_click = r->connectTo (this, event_activated); + region_attach = r->connectTo (this, mediatype_attached); + r->repaint (); + tr->clipStart (); + Transition * trans = convertNode <Transition> (trans_in); + if (trans && trans->supported ()) { + active_trans = trans_in; + trans_step = 1; + if (Transition::Fade == trans->type) { + trans_steps = trans->dur; + trans_timer = document()->setTimeout(this, 100, trans_timer_id); + } else { + trans_steps = 4 * trans->dur; + trans_timer = document()->setTimeout(this, 25, trans_timer_id); + } + } + if (Runtime::dur_timer == tr->durTime().durval && + tr->durTime().offset > 0) { + // FIXME: also account for fill duration + trans = convertNode <Transition> (trans_out); + if (trans && trans->supported () && + (int) trans->dur < tr->durTime().offset) + trans_out_timer = document()->setTimeout ( + this, + (tr->durTime().offset - trans->dur) * 100, + trans_out_timer_id); + } + } else + kdWarning () << nodeName() << "::begin " << src << " region '" << + param (StringPool::attr_region) << "' not found" << endl; + TimedMrl::begin (); +} + +KDE_NO_EXPORT void SMIL::MediaType::finish () { + if (trans_timer && !keepContent (this)) { + document ()->cancelTimer (trans_timer); + ASSERT(!trans_timer); + } + if (region_node) + convertNode <SMIL::RegionBase> (region_node)->repaint (); + TimedMrl::finish (); + static_cast <MediaTypeRuntime *> (runtime ())->clipStop (); +} + +/** + * Re-implement from TimedMrl, because we may have children like + * param/set/animatie that should all be activate, but also other smil or imfl + * documents, that should only be activated if the runtime has started + */ +KDE_NO_EXPORT void SMIL::MediaType::childDone (NodePtr child) { + bool child_doc = child->mrl () && child->mrl ()->opener.ptr () == this; + if (child_doc) { + child->deactivate (); // should only if fill not is freeze or hold + } else if (active ()) { // traverse param or area children + for (NodePtr c = child->nextSibling(); c; c = c->nextSibling ()) + if (!c->mrl () || c->mrl ()->opener.ptr () != this ) { + c->activate (); + return; + } + Runtime * tr = runtime (); + if (tr->state () < Runtime::timings_stopped) { + if (tr->state () == Runtime::timings_started) + tr->propagateStop (child_doc); // what about repeat_count .. + return; // still running, wait for runtime to finish + } + } + if (active ()) + finish (); +} + +KDE_NO_EXPORT bool SMIL::MediaType::needsVideoWidget () { + MediaTypeRuntime * mtr = static_cast <MediaTypeRuntime *> (runtime ()); + SMIL::Smil * s = SMIL::Smil::findSmilNode (this); + Node * link = s ? s->current_av_media_type.ptr () : 0L; + return ((link == this || !link) && + (state == state_deferred || unfinished ()) && link && + mtr->state () != Runtime::timings_stopped && + (!strcmp (nodeName (), "video") || !strcmp (nodeName (), "ref")) && + surface ()); +} + +SurfacePtr SMIL::MediaType::getSurface (NodePtr node) { + resetSurface (); + Surface *s = surface (); + if (s && node) + s->node = node; + return s; +} + +KDE_NO_EXPORT Surface *SMIL::MediaType::surface () { + if (!keepContent (this)) { + resetSurface (); + return NULL; + } + if (!sub_surface) { + SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node); + if (rb && rb->surface ()) { + SRect rect = calculateBounds (); + sub_surface =rb->region_surface->createSurface (this, rect); + if (width > 0 && height > 0) { + sub_surface->xscale = 1.0 * rect.width () / width; + sub_surface->yscale = 1.0 * rect.height () / height; + } + //kdDebug() << sub_surface.ptr() << " " << nodeName() << " " << src << " " << rr.width() << "," << rr.height() << " => " << x << "," << y << w << "," << h << endl; + } + } + return sub_surface.ptr (); +} + +KDE_NO_EXPORT void SMIL::MediaType::resetSurface () { + if (sub_surface) + sub_surface->remove (); + sub_surface = NULL; +} + +KDE_NO_EXPORT SRect SMIL::MediaType::calculateBounds () { + SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node); + if (rb && rb->surface ()) { + SRect rr = rb->region_surface->bounds; + Single x, y, w = width, h = height; + sizes.calcSizes (this, rr.width(), rr.height(), x, y, w, h); + if (width > 0 && height > 0 && w > 0 && h > 0) + switch (fit) { + case fit_meet: { + float iasp = 1.0 * width / height; + float rasp = 1.0 * w / h; + if (iasp > rasp) + h = height * w / width; + else + w = width * h / height; + break; + } + case fit_scroll: + case fit_hidden: + w = width; + h = height; + break; + case fit_slice: { + float iasp = 1.0 * width / height; + float rasp = 1.0 * w / h; + if (iasp > rasp) + w = width * h / height; + else + h = height * w / width; + break; + } + default: {} // fit_fill + } + return SRect (x, y, w, h); + } + return SRect (); +} + +bool SMIL::MediaType::handleEvent (EventPtr event) { + Surface *s = surface(); + switch (event->id ()) { + case event_postponed: { + PostponedEvent * pe = static_cast <PostponedEvent *> (event.ptr ()); + static_cast<MediaTypeRuntime*>(runtime())->postpone (pe->is_postponed); + return true; + } + case event_timer: { + TimerEvent * te = static_cast <TimerEvent *> (event.ptr ()); + if (te && te->timer_info) { + if (te->timer_info->event_id == trans_timer_id) { + if (trans_step >= trans_steps) + active_trans = NULL; + else + te->interval = trans_step++ < trans_steps; + if (s && s->parentNode()) + s->parentNode()->repaint (s->bounds); + return true; + } else if (te->timer_info->event_id == trans_out_timer_id) { + active_trans = trans_out; + Transition * trans = convertNode <Transition> (trans_out); + if (trans) { + if (trans_timer) // eg. overlapping transIn/transOut + document ()->cancelTimer (trans_timer); + trans_step = 1; + if (Transition::Fade == trans->type) { + trans_steps = trans->dur; + trans_timer = document()->setTimeout(this, 100, trans_timer_id); + } else { + trans_steps = 4 * trans->dur; + trans_timer = document()->setTimeout(this, 25, trans_timer_id); + } + trans_out_active = true; + if (s) + s->repaint (); + } + return true; + } + } + } // fall through + default: + return TimedMrl::handleEvent (event); + } +} + +KDE_NO_EXPORT NodeRefListPtr SMIL::MediaType::listeners (unsigned int id) { + NodeRefListPtr l = mouse_listeners.listeners (id); + if (l) + return l; + switch (id) { + case mediatype_attached: + return m_MediaAttached; + } + return TimedMrl::listeners (id); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +SMIL::AVMediaType::AVMediaType (NodePtr & d, const QString & t) + : SMIL::MediaType (d, t, id_node_audio_video) {} + +KDE_NO_EXPORT NodePtr SMIL::AVMediaType::childFromTag (const QString & tag) { + return fromXMLDocumentTag (m_doc, tag); +} + +KDE_NO_EXPORT void SMIL::AVMediaType::defer () { + setState (state_deferred); + MediaTypeRuntime * mr = static_cast <MediaTypeRuntime *> (runtime ()); + if (mr->state () == Runtime::timings_started) + mr->postpone_lock = document ()->postpone (); +} + +KDE_NO_EXPORT void SMIL::AVMediaType::undefer () { + setState (state_activated); + MediaTypeRuntime * mr = static_cast <MediaTypeRuntime *> (runtime ()); + if (mr->state () == Runtime::timings_started) { + mr->postpone_lock = 0L; + mr->started (); + } +} + +KDE_NO_EXPORT void SMIL::AVMediaType::endOfFile () { + if (!active()) + return; // backend eof after a reset + MediaTypeRuntime * mr = static_cast <MediaTypeRuntime *> (runtime ()); + mr->postpone_lock = 0L; + mr->propagateStop (true); +} + +KDE_NO_EXPORT Runtime * SMIL::AVMediaType::getNewRuntime () { + return new AudioVideoData (this); +} + +KDE_NO_EXPORT void SMIL::AVMediaType::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT bool SMIL::AVMediaType::expose () const { + return !src.isEmpty () && !external_tree; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +SMIL::ImageMediaType::ImageMediaType (NodePtr & d) + : SMIL::MediaType (d, "img", id_node_img) {} + +KDE_NO_EXPORT Runtime * SMIL::ImageMediaType::getNewRuntime () { + return new ImageRuntime (this); +} + +KDE_NO_EXPORT NodePtr SMIL::ImageMediaType::childFromTag (const QString & tag) { + if (!strcmp (tag.latin1 (), "imfl")) + return new RP::Imfl (m_doc); + return SMIL::MediaType::childFromTag (tag); +} + +KDE_NO_EXPORT void SMIL::ImageMediaType::accept (Visitor * v) { + v->visit (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +SMIL::TextMediaType::TextMediaType (NodePtr & d) + : SMIL::MediaType (d, "text", id_node_text) {} + +KDE_NO_EXPORT Runtime * SMIL::TextMediaType::getNewRuntime () { + return new TextRuntime (this); +} + +KDE_NO_EXPORT void SMIL::TextMediaType::accept (Visitor * v) { + v->visit (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +SMIL::RefMediaType::RefMediaType (NodePtr & d) + : SMIL::MediaType (d, "ref", id_node_ref) {} + +KDE_NO_EXPORT Runtime * SMIL::RefMediaType::getNewRuntime () { + return new AudioVideoData (this); // FIXME check mimetype first +} + +KDE_NO_EXPORT void SMIL::RefMediaType::accept (Visitor * v) { + v->visit (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT SMIL::Brush::Brush (NodePtr & d) + : SMIL::MediaType (d, "brush", id_node_brush) {} + +KDE_NO_EXPORT void SMIL::Brush::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT Runtime * SMIL::Brush::getNewRuntime () { + return new MediaTypeRuntime (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT Runtime * SMIL::Set::getNewRuntime () { + return new SetData (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT Runtime * SMIL::Animate::getNewRuntime () { + return new AnimateData (this); +} + +KDE_NO_EXPORT bool SMIL::Animate::handleEvent (EventPtr event) { + if (event->id () == event_timer) { + TimerEvent * te = static_cast <TimerEvent *> (event.ptr ()); + if (te && te->timer_info && te->timer_info->event_id == anim_timer_id) { + if (static_cast <AnimateData *> (runtime ())->timerTick () && + te->timer_info) + te->interval = true; + return true; + } + } + return TimedMrl::handleEvent (event); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT Runtime *SMIL::AnimateMotion::getNewRuntime () { + return new AnimateMotionData (this); +} + +KDE_NO_EXPORT bool SMIL::AnimateMotion::handleEvent (EventPtr event) { + if (event->id () == event_timer) { + TimerEvent * te = static_cast <TimerEvent *> (event.ptr ()); + if (te && te->timer_info && te->timer_info->event_id == anim_timer_id) { + if (static_cast <AnimateMotionData *> (runtime ())->timerTick () && + te->timer_info) + te->interval = true; + return true; + } + } + return TimedMrl::handleEvent (event); +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void SMIL::Param::activate () { + setState (state_activated); + QString name = getAttribute (StringPool::attr_name); + Node * parent = parentNode ().ptr (); + if (!name.isEmpty () && parent && parent->isElementNode ()) + static_cast<Element*>(parent)->setParam (name, + getAttribute (StringPool::attr_value)); + Element::activate (); //finish (); // no livetime of itself, will deactivate +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT void Visitor::visit (SMIL::Region * n) { + visit (static_cast <SMIL::RegionBase *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::Layout * n) { + visit (static_cast <SMIL::RegionBase *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::Transition * n) { + visit (static_cast <Element *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::TimedMrl * n) { + visit (static_cast <Element *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::MediaType * n) { + visit (static_cast <SMIL::TimedMrl *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::ImageMediaType * n) { + visit (static_cast <SMIL::MediaType *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::TextMediaType * n) { + visit (static_cast <SMIL::MediaType *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::RefMediaType * n) { + visit (static_cast <SMIL::MediaType *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::AVMediaType * n) { + visit (static_cast <SMIL::MediaType *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::Brush * n) { + visit (static_cast <SMIL::MediaType *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::Anchor * n) { + visit (static_cast <SMIL::LinkingBase *> (n)); +} + +KDE_NO_EXPORT void Visitor::visit (SMIL::Area * n) { + visit (static_cast <SMIL::LinkingBase *> (n)); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT ImageRuntime::ImageRuntime (NodePtr e) + : MediaTypeRuntime (e), img_movie (0L) +{} + +KDE_NO_CDTOR_EXPORT ImageRuntime::~ImageRuntime () { + delete img_movie; +} + +KDE_NO_EXPORT +bool ImageRuntime::parseParam (const TrieString & name, const QString & val) { + //kdDebug () << "ImageRuntime::param " << name << "=" << val << endl; + if (name == StringPool::attr_src) { + killWGet (); + NodePtr element_protect = element; + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (!mt) + return false; // can not happen + if (mt->external_tree) + mt->removeChild (mt->external_tree); + mt->src = val; + if (!val.isEmpty ()) { + QString abs = mt->absolutePath (); + cached_img.setUrl (abs); + if (cached_img.isEmpty ()) { + wget (abs); + } else { + mt->width = cached_img.data->image->width (); + mt->height = cached_img.data->image->height (); + } + } + } else + return MediaTypeRuntime::parseParam (name, val); + return true; +} + +/** + * start_timer timer expired, repaint if we have an image + */ +KDE_NO_EXPORT void ImageRuntime::started () { + if (element && downloading ()) { + postpone_lock = element->document ()->postpone (); + return; + } + MediaTypeRuntime::started (); +} + +KDE_NO_EXPORT void ImageRuntime::clipStart () { + if (img_movie) { + img_movie->restart (); + if (img_movie->paused ()) + img_movie->unpause (); + } + MediaTypeRuntime::clipStart (); +} + +KDE_NO_EXPORT void ImageRuntime::clipStop () { + if (img_movie && frame_nr) + img_movie->pause (); + MediaTypeRuntime::clipStop (); +} + +KDE_NO_EXPORT void ImageRuntime::remoteReady (QByteArray & data) { + NodePtr element_protect = element; // note element is weak + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (data.size () && mt) { + mt->resetSurface (); + QString mime = mimetype (); + kdDebug () << "ImageRuntime::remoteReady " << mime << " empty:" << cached_img.isEmpty () << " " << mt->src << endl; + if (mime.startsWith (QString::fromLatin1 ("text/"))) { + QTextStream ts (data, IO_ReadOnly); + readXML (element, ts, QString ()); + Mrl *mrl = mt->external_tree ? mt->external_tree->mrl () : NULL; + if (mrl) { + mt->width = mrl->width; + mt->height = mrl->height; + } + } + if (!mt->external_tree && cached_img.isEmpty ()) { + delete img_movie; + img_movie = 0L; + QImage *pix = new QImage (data); + if (!pix->isNull ()) { + cached_img.data->image = pix; + img_movie = new QMovie (data, data.size ()); + img_movie->connectUpdate(this,SLOT(movieUpdated(const QRect&))); + img_movie->connectStatus (this, SLOT (movieStatus (int))); + img_movie->connectResize(this,SLOT (movieResize(const QSize&))); + frame_nr = 0; + mt->width = pix->width (); + mt->height = pix->height (); + if (mt->surface ()) + mt->sub_surface->repaint (); + } else + delete pix; + } + } + postpone_lock = 0L; + if (timingstate == timings_started) + started (); +} + +KDE_NO_EXPORT void ImageRuntime::movieUpdated (const QRect &) { + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (mt && frame_nr++) { + mt->resetSurface (); + cached_img.setUrl (QString ()); + ASSERT (cached_img.data && cached_img.isEmpty ()); + cached_img.data->image = new QImage; + *cached_img.data->image = (img_movie->framePixmap ()); + if (mt->surface()) + mt->sub_surface->repaint (); + } + if (timingstate != timings_started && img_movie) + img_movie->pause (); +} + +KDE_NO_EXPORT void ImageRuntime::movieStatus (int s) { + if (element && element->state >= Node::state_began && + SMIL::TimedMrl::keepContent (element)) { + if (s == QMovie::EndOfMovie) { + propagateStop (false); + } + } +} + +KDE_NO_EXPORT void ImageRuntime::movieResize (const QSize &) { + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (mt->surface ()) + mt->sub_surface->repaint (); + //kdDebug () << "movieResize" << endl; +} + +KDE_NO_EXPORT void ImageRuntime::postpone (bool b) { + kdDebug () << "ImageRuntime::postpone " << b << endl; + if (img_movie) { + if (!img_movie->paused () && b) + img_movie->pause (); + else if (img_movie->paused () && !b) + img_movie->unpause (); + } +} + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + class TextRuntimePrivate { + public: + TextRuntimePrivate () { + reset (); + } + void reset () { + codec = 0L; + font = QApplication::font (); + data.truncate (0); + } + QByteArray data; + QTextCodec * codec; + QFont font; + }; +} + +KDE_NO_CDTOR_EXPORT TextRuntime::TextRuntime (NodePtr e) + : MediaTypeRuntime (e), d (new TextRuntimePrivate) { + reset (); +} + +KDE_NO_CDTOR_EXPORT TextRuntime::~TextRuntime () { + delete d; +} + +KDE_NO_EXPORT void TextRuntime::reset () { + d->reset (); + font_size = d->font.pointSize (); + font_color = 0; + background_color = 0xffffff; + bg_opacity = 100; + halign = align_left; + MediaTypeRuntime::reset (); +} + +KDE_NO_EXPORT +bool TextRuntime::parseParam (const TrieString & name, const QString & val) { + //kdDebug () << "TextRuntime::parseParam " << name << "=" << val << endl; + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (!mt) + return false; // cannot happen + if (name == StringPool::attr_src) { + killWGet (); + mt->src = val; + d->data.resize (0); + if (!val.isEmpty ()) + wget (mt->absolutePath ()); + return true; + } + if (name == "backgroundColor" || name == "background-color") { + background_color = val.isEmpty () ? 0xffffff : QColor (val).rgb (); + } else if (name == "fontColor") { + font_color = val.isEmpty () ? 0 : QColor (val).rgb (); + } else if (name == "charset") { + d->codec = QTextCodec::codecForName (val.ascii ()); + } else if (name == "fontFace") { + ; //FIXME + } else if (name == "fontPtSize") { + font_size = val.isEmpty () ? d->font.pointSize () : val.toInt (); + } else if (name == "fontSize") { + font_size += val.isEmpty () ? d->font.pointSize () : val.toInt (); + } else if (name == "backgroundOpacity") { + bg_opacity = (int) SizeType (val).size (100); + } else if (name == "hAlign") { + const char * cval = val.ascii (); + if (!cval) + halign = align_left; + else if (!strcmp (cval, "center")) + halign = align_center; + else if (!strcmp (cval, "right")) + halign = align_right; + else + halign = align_left; + // TODO: expandTabs fontBackgroundColor fontSize fontStyle fontWeight hAlig vAlign wordWrap + } else + return MediaTypeRuntime::parseParam (name, val); + mt->resetSurface (); + if (mt->surface ()) + mt->sub_surface->repaint (); + return true; +} + +/** + * start_timer timer expired, repaint if we have text + */ +KDE_NO_EXPORT void TextRuntime::started () { + if (element && downloading ()) { + postpone_lock = element->document ()->postpone (); + return; + } + MediaTypeRuntime::started (); +} + +KDE_NO_EXPORT void TextRuntime::remoteReady (QByteArray & data) { + QString str (data); + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element); + if (mt && data.size ()) { + d->data = data; + mt->resetSurface (); + if (d->data.size () > 0 && !d->data [d->data.size () - 1]) + d->data.resize (d->data.size () - 1); // strip zero terminate char + QTextStream ts (d->data, IO_ReadOnly); + if (d->codec) + ts.setCodec (d->codec); + text = ts.read (); + if (mt->surface ()) + mt->sub_surface->repaint (); + } + postpone_lock = 0L; + if (timingstate == timings_started) + started (); +} + +//----------------------------------------------------------------------------- + +#include "kmplayer_smil.moc" diff --git a/src/kmplayer_smil.h b/src/kmplayer_smil.h new file mode 100644 index 0000000..3ecfd18 --- /dev/null +++ b/src/kmplayer_smil.h @@ -0,0 +1,898 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2005-2007 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYER_SMILL_H_ +#define _KMPLAYER_SMILL_H_ + +#include <config.h> +#include <qobject.h> +#include <qstring.h> +#include <qstringlist.h> + +#include "kmplayerplaylist.h" + +class QTextStream; +class QImage; +class QPainter; + +namespace KIO { + class Job; +} + +struct TransTypeInfo; + +namespace KMPlayer { + +struct KMPLAYER_NO_EXPORT ImageData { + ImageData( const QString & img); + ~ImageData(); + QImage *image; +private: + QString url; +}; + +typedef SharedPtr <ImageData> ImageDataPtr; +typedef WeakPtr <ImageData> ImageDataPtrW; + +struct KMPLAYER_NO_EXPORT CachedImage { + void setUrl (const QString & url); + bool isEmpty (); + ImageDataPtr data; +}; + +class TextRuntimePrivate; + +/* + * Event signaled before the actual starting takes place. Use by SMIL::Excl + * to stop possible other children + */ +class ToBeStartedEvent : public Event { +public: + ToBeStartedEvent (NodePtr n); + NodePtrW node; +}; + +/* + * Interpretation of sizes + */ +class KMPLAYER_NO_EXPORT SizeType { +public: + SizeType (); + SizeType (const QString & s); + void reset (); + SizeType & operator = (const QString & s); + SizeType & operator += (const SizeType & s); + SizeType & operator -= (const SizeType & s); + SizeType & operator /= (const int i) + { perc_size /= i; abs_size /= i; return *this; } + SizeType & operator *= (const float f) + { perc_size *= f; abs_size *= f; return *this; } + Single size (Single relative_to = 100) const; + bool isSet () const { return isset; } +private: + Single perc_size; + Single abs_size; + bool isset; +}; + +/** + * For RegPoint, RegionRuntime and MediaRuntime, having sizes + */ +class KMPLAYER_NO_EXPORT CalculatedSizer { +public: + KDE_NO_CDTOR_EXPORT CalculatedSizer () {} + KDE_NO_CDTOR_EXPORT ~CalculatedSizer () {} + + void resetSizes (); + void calcSizes (Node *, Single w, Single h, + Single & xoff, Single & yoff, Single & w1, Single & h1); + bool applyRegPoints (Node *, Single w, Single h, + Single & xoff, Single & yoff, Single & w1, Single & h1); + SizeType left, top, width, height, right, bottom; + QString reg_point, reg_align; + bool setSizeParam (const TrieString &name, const QString &value, bool &dim); + void move (const SizeType &x, const SizeType &y); +}; + +/** + * Live representation of a SMIL element having timings + */ +class KMPLAYER_NO_EXPORT Runtime { +public: + enum TimingState { + timings_reset = 0, timings_began, timings_started, timings_stopped + }; + enum DurationTime { begin_time = 0, duration_time, end_time, durtime_last }; + enum Duration { + dur_infinite = -1, dur_timer = 0, dur_media, + dur_activated, dur_inbounds, dur_outbounds, + dur_end, dur_start, dur_last_dur + }; + Runtime (NodePtr e); + virtual ~Runtime (); + /** + * Called when element is pulled in scope, from Node::activate() + */ + virtual void begin (); + virtual void beginAndStart (); // skip start timer (if any) + /** + * Reset all data, called from end() and init() + */ + virtual void reset (); + virtual bool parseParam (const TrieString & name, const QString & value); + TimingState state () const { return timingstate; } + void propagateStop (bool forced); + void propagateStart (); + void processEvent (unsigned int event); + /** + * Duration items, begin/dur/end, length information or connected element + */ + struct DurationItem { + DurationItem () : durval (dur_timer), offset (0) {} + Duration durval; + int offset; + ConnectionPtr connection; + } durations [(const int) durtime_last]; + virtual void started (); + virtual void stopped (); + KDE_NO_EXPORT DurationItem & beginTime () { return durations[begin_time]; } + KDE_NO_EXPORT DurationItem & durTime () { return durations[duration_time]; } + KDE_NO_EXPORT DurationItem & endTime () { return durations [end_time]; } +private: + void setDurationItem (DurationTime item, const QString & val); +public: + TimingState timingstate; +protected: + NodePtrW element; + TimerInfoPtrW start_timer; + TimerInfoPtrW duration_timer; + int repeat_count; +}; + +/** + * Some common runtime data for all mediatype classes + */ +class KMPLAYER_NO_EXPORT MediaTypeRuntime : public RemoteObject,public Runtime { +public: + ~MediaTypeRuntime (); + virtual void reset (); + virtual void stopped (); + virtual void postpone (bool b); + virtual void clipStart (); + virtual void clipStop (); + PostponePtr postpone_lock; + MediaTypeRuntime (NodePtr e); +protected: + ConnectionPtr document_postponed; // pause audio/video accordantly +}; + +/** + * Data needed for audio/video clips + */ +class KMPLAYER_NO_EXPORT AudioVideoData : public MediaTypeRuntime { +public: + AudioVideoData (NodePtr e); + virtual bool isAudioVideo (); + virtual bool parseParam (const TrieString & name, const QString & value); + virtual void started (); + virtual void postpone (bool b); + virtual void clipStart (); + virtual void clipStop (); +}; + +class KMPLAYER_NO_EXPORT ImageRuntime : public QObject,public MediaTypeRuntime { + Q_OBJECT +public: + ImageRuntime (NodePtr e); + ~ImageRuntime (); + virtual bool parseParam (const TrieString & name, const QString & value); + virtual void postpone (bool b); + virtual void clipStart (); + virtual void clipStop (); + QMovie * img_movie; + CachedImage cached_img; + int frame_nr; +protected: + virtual void started (); + virtual void remoteReady (QByteArray &); +private slots: + void movieUpdated (const QRect &); + void movieStatus (int); + void movieResize (const QSize &); +}; + +/** + * Data needed for text + */ +class KMPLAYER_NO_EXPORT TextRuntime : public MediaTypeRuntime { +public: + TextRuntime (NodePtr e); + ~TextRuntime (); + void reset (); + virtual bool parseParam (const TrieString & name, const QString & value); + int font_size; + unsigned int font_color; + unsigned int background_color; + int bg_opacity; + enum { align_left, align_center, align_right } halign; + QString text; + TextRuntimePrivate * d; +protected: + virtual void started (); + virtual void remoteReady (QByteArray &); +}; + +/** + * Stores runtime data of elements from animate group set/animate/.. + */ +class KMPLAYER_NO_EXPORT AnimateGroupData : public Runtime { +public: + KDE_NO_CDTOR_EXPORT ~AnimateGroupData () {} + virtual bool parseParam (const TrieString & name, const QString & value); + virtual void reset (); +protected: + void restoreModification (); + AnimateGroupData (NodePtr e); + NodePtrW target_element; + TrieString changed_attribute; + QString change_to; + int modification_id; +protected: + virtual void stopped (); +}; + +/** + * Stores runtime data of set element + */ +class KMPLAYER_NO_EXPORT SetData : public AnimateGroupData { +public: + KDE_NO_CDTOR_EXPORT SetData (NodePtr e) : AnimateGroupData (e) {} + KDE_NO_CDTOR_EXPORT ~SetData () {} +protected: + virtual void started (); +}; + +/** + * Stores runtime data of animate element + */ +class KMPLAYER_NO_EXPORT AnimateData : public AnimateGroupData { +public: + AnimateData (NodePtr e); + KDE_NO_CDTOR_EXPORT ~AnimateData () {} + virtual bool parseParam (const TrieString & name, const QString & value); + virtual void reset (); + virtual void started (); + virtual void stopped (); + bool timerTick(); +private: + void applyStep (); + TimerInfoPtrW anim_timer; + enum { acc_none, acc_sum } accumulate; + enum { add_replace, add_sum } additive; + int change_by; + enum { calc_discrete, calc_linear, calc_paced, calc_spline } calcMode; + QString change_from; + QStringList change_values; + int steps; + float change_delta, change_to_val, change_from_val; + QString change_from_unit; +}; + +/** + * Stores runtime data of animate element + */ +class KMPLAYER_NO_EXPORT AnimateMotionData : public AnimateGroupData { +public: + AnimateMotionData (NodePtr e); + ~AnimateMotionData (); + virtual bool parseParam (const TrieString & name, const QString & value); + virtual void reset (); + virtual void started (); + virtual void stopped (); + bool timerTick(); +private: + bool checkTarget (Node *n); + bool setInterval (); + void applyStep (); + bool getCoordinates (const QString &coord, SizeType &x, SizeType &y); + TimerInfoPtrW anim_timer; + enum { acc_none, acc_sum } accumulate; + enum { add_replace, add_sum } additive; + enum { calc_discrete, calc_linear, calc_paced, calc_spline } calcMode; + QString change_from; + QString change_by; + QStringList values; + float *keytimes; + int keytime_count; + QStringList splines; + float control_point[4]; + unsigned int steps; + unsigned int cur_step; + unsigned int keytime_steps; + unsigned int interval; + SizeType begin_x, begin_y; + SizeType cur_x, cur_y; + SizeType delta_x, delta_y; + SizeType end_x, end_y; +}; + +class KMPLAYER_NO_EXPORT MouseListeners { +public: + MouseListeners(); + + NodeRefListPtr listeners (unsigned int event_id); + + NodeRefListPtr m_ActionListeners; // mouse clicked + NodeRefListPtr m_OutOfBoundsListeners; // mouse left + NodeRefListPtr m_InBoundsListeners; // mouse entered +}; + +/** + * Translates string to deci-seconds or 'special' high number + */ +bool parseTime (const QString & val, int & dur /*,const QString & dateformat*/); + +//----------------------------------------------------------------------------- + +namespace SMIL { + +const short id_node_smil = 100; +const short id_node_head = 101; +const short id_node_layout = 103; +const short id_node_root_layout = 104; +const short id_node_region = 105; +const short id_node_regpoint = 106; +const short id_node_transition = 107; +const short id_node_body = 110; +const short id_node_par = 111; +const short id_node_seq = 112; +const short id_node_switch = 113; +const short id_node_excl = 114; +const short id_node_img = 120; +const short id_node_audio_video = 121; +const short id_node_text = 122; +const short id_node_ref = 123; +const short id_node_brush = 124; +const short id_node_set = 132; +const short id_node_animate = 133; +const short id_node_title = 140; +const short id_node_param = 141; +const short id_node_meta = 142; +const short id_node_anchor = 150; +const short id_node_area = 151; +const short id_node_first = id_node_smil; +const short id_node_first_timed_mrl = id_node_body; +const short id_node_last_timed_mrl = id_node_animate; +const short id_node_first_mediatype = id_node_img; +const short id_node_last_mediatype = id_node_brush; +const short id_node_first_group = id_node_body; +const short id_node_last_group = id_node_excl; +const short id_node_last = 200; // reserve 100 ids + +/** + * '<smil>' tag + */ +class Smil : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Smil (NodePtr & d) : Mrl (d, id_node_smil) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "smil"; } + PlayType playType () { return play_type_video; } + void activate (); + void deactivate (); + void closed (); + void childDone (NodePtr child); + bool expose () const; + bool handleEvent (EventPtr event); + void accept (Visitor *); + void jump (const QString & id); + static Smil * findSmilNode (Node * node); + /** + * Hack to mark the currently playing MediaType as finished + * FIXME: think of a descent callback way for this + */ + Mrl * linkNode (); + NodePtrW current_av_media_type; + NodePtrW layout_node; +}; + +/** + * Represents optional 'head' tag of SMIL document as in + * <smil><head/><body/></smil> + */ +class KMPLAYER_NO_EXPORT Head : public Element { +public: + KDE_NO_CDTOR_EXPORT Head (NodePtr & d) : Element (d, id_node_head) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "head"; } + void closed (); + void childDone (NodePtr child); + bool expose () const; +}; + +/** + * Base class for SMIL::Region, SMIL::RootLayout and SMIL::Layout + */ +class KMPLAYER_NO_EXPORT RegionBase : public RemoteObject, public Element { +public: + enum ShowBackground { ShowAlways, ShowWhenActive }; + + ~RegionBase (); + bool expose () const { return false; } + void activate (); + void childDone (NodePtr child); + void deactivate (); + virtual void parseParam (const TrieString & name, const QString & value); + /** + * repaints region, calls scheduleRepaint(x,y,w,h) on view + */ + void repaint (); + void repaint (const SRect & rect); + /** + * calculate the relative x,y,w,h on the child region elements + * given this element's w and h value + * and child's left/top/right/width/height/bottom attributes + */ + virtual void updateDimensions (); + void boundsUpdate (); // recalculates and repaint old and new bounds + + virtual Surface *surface (); + SurfacePtrW region_surface; + CachedImage cached_img; + CalculatedSizer sizes; + + Single x, y, w, h; // unscaled values + int z_order; + unsigned int background_color; + QString background_image; + ShowBackground show_background; +protected: + RegionBase (NodePtr & d, short id); + PostponePtr postpone_lock; // pause while loading bg image + virtual void remoteReady (QByteArray &); // image downloaded +}; + +/** + * Defines region layout, should reside below 'head' element + */ +class KMPLAYER_NO_EXPORT Layout : public RegionBase { +public: + Layout (NodePtr & d); + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "layout"; } + void activate (); + void closed (); + virtual void accept (Visitor *); + /** + * recursively calculates dimensions of this and child regions + */ + virtual void updateDimensions (); + virtual Surface *surface (); + + NodePtrW rootLayout; +}; + +/** + * Represents a rectangle on the viewing area + */ +class KMPLAYER_NO_EXPORT Region : public RegionBase { +public: + Region (NodePtr & d); + KDE_NO_EXPORT const char * nodeName () const { return "region"; } + NodePtr childFromTag (const QString & tag); + void calculateBounds (Single w, Single h); + virtual NodeRefListPtr listeners (unsigned int event_id); + virtual void accept (Visitor *); + /** + * boolean for check if pointerEntered/pointerLeft should be called by View + */ + bool has_mouse; + NodeRefListPtr m_AttachedMediaTypes; // active attached mediatypes +private: + MouseListeners mouse_listeners; +}; + +/** + * Represents the root area for the other regions + */ +class KMPLAYER_NO_EXPORT RootLayout : public RegionBase { +public: + KDE_NO_CDTOR_EXPORT RootLayout (NodePtr & d) + : RegionBase (d, id_node_root_layout) {} + KDE_NO_EXPORT const char * nodeName () const { return "root-layout"; } +}; + +/** + * Represents a regPoint element for alignment inside regions + */ +class KMPLAYER_NO_EXPORT RegPoint : public Element { +public: + KDE_NO_CDTOR_EXPORT RegPoint (NodePtr & d) : Element(d, id_node_regpoint) {} + KDE_NO_CDTOR_EXPORT ~RegPoint () {} + KDE_NO_EXPORT const char * nodeName () const { return "regPoint"; } + KDE_NO_EXPORT bool expose () const { return false; } + void parseParam (const TrieString & name, const QString & value); + CalculatedSizer sizes; +}; + +/** + * Represents a transition element for starting media types + */ +class KMPLAYER_NO_EXPORT Transition : public Element { +public: + enum TransType { + TransTypeNone = 0, + BarWipe, IrisWipe, ClockWipe, SnakeWipe, // required, TODO + BoxWipe, FourBoxWipe, BarnDoorWipe, DiagonalWipe, BowTieWipe, + MiscDiagonalWipe, VeeWipe, BarnVeeWipe, ZigZagWipe, BarnZigZagWipe, + TriangleWipe, ArrowHeadWipe, PentagonWipe, HexagonWipe, EllipseWipe, + EyeWipe, RoundRectWipe, StarWipe, MiscShapeWipe, + PinWheelWipe, SingleSweepWipe, FanWipe, DoubleFanWipe, + DoubleSweepWipe, SaloonDoorWipe, WindShieldWipe, + SpiralWipe, ParallelSnakesWipe, BoxSnakesWipe, WaterFallWipe, + PushWipe, SideWipe, Fade, + TransLast + }; + enum TransSubType { + SubTransTypeNone = 0, + SubLeftToRight, SubTopToBottom, SubTopLeft, SubTopRight, + SubBottomRight, SubBottomLeft, + SubTopCenter, SubRightCenter, SubBottomCenter, SubLeftCenter, + SubCornersIn, SubCornersOut, + SubCircle, SubVertical, SubHorizontal, + SubFromLeft, SubFromTop, SubFromRight, SubFromBottom, + SubCrossfade, SubFadeToColor, SubFadeFromColor, + SubRectangle, SubDiamond, + SubClockwiseTwelve, SubClockwiseThree, SubClockwiseSix, + SubClockwiseNine, + // and lots more .. TODO + SubTransLast + }; + Transition (NodePtr & d); + KDE_NO_CDTOR_EXPORT ~Transition () {} + void activate (); + KDE_NO_EXPORT void accept (Visitor * v) { v->visit (this); } + KDE_NO_EXPORT const char * nodeName () const { return "transition"; } + void parseParam (const TrieString & name, const QString & value); + KDE_NO_EXPORT bool expose () const { return false; } + bool supported (); + TransType type; + TransSubType sub_type; + TransTypeInfo *type_info; + enum { dir_forward, dir_reverse } direction; + int dur; // deci seconds + float start_progress, end_progress; + unsigned int fade_color; +}; + +/** + * Base for all SMIL media elements having begin/dur/end/.. attributes + */ +class KMPLAYER_NO_EXPORT TimedMrl : public Mrl { +public: + enum Fill { + fill_default, fill_inherit, fill_remove, fill_freeze, + fill_hold, fill_transition, fill_auto + }; + ~TimedMrl (); + void closed (); + void activate (); + void begin (); + void finish (); + void deactivate (); + void reset (); + bool expose () const { return false; } + void childBegan (NodePtr child); + void childDone (NodePtr child); + virtual bool handleEvent (EventPtr event); + virtual NodeRefListPtr listeners (unsigned int event_id); + KDE_NO_EXPORT void accept (Visitor * v) { v->visit (this); } + void init (); + virtual void parseParam (const TrieString &, const QString &); + Runtime * runtime (); + static Runtime::DurationItem * getDuration (NodePtr n); + static bool isTimedMrl (const Node *n); + static bool keepContent (Node *n); + static Fill getDefaultFill (NodePtr n); + unsigned int begin_time; + unsigned int finish_time; + Fill fill; + Fill fill_def; + Fill fill_active; +protected: + TimedMrl (NodePtr & d, short id); + virtual Runtime * getNewRuntime (); + + NodeRefListPtr m_StartListeners; // Element about to be started + NodeRefListPtr m_StartedListeners; // Element is started + NodeRefListPtr m_StoppedListeners; // Element stopped + Runtime * m_runtime; +}; + +KDE_NO_EXPORT inline Runtime * TimedMrl::runtime () { + if (!m_runtime) + m_runtime = getNewRuntime (); + return m_runtime; +} + +KDE_NO_EXPORT inline bool TimedMrl::isTimedMrl (const Node *n) { + return n && + n->id >= id_node_first_timed_mrl && + n->id <= id_node_last_timed_mrl; +} + +/** + * Abstract base for the group elements (par/seq/excl/..) + */ +class KMPLAYER_NO_EXPORT GroupBase : public TimedMrl { +public: + KDE_NO_CDTOR_EXPORT ~GroupBase () {} + NodePtr childFromTag (const QString & tag); + PlayType playType () { return play_type_none; } + void finish (); + void deactivate (); + void setJumpNode (NodePtr); +protected: + KDE_NO_CDTOR_EXPORT GroupBase (NodePtr & d, short id) : TimedMrl (d, id) {} + NodePtrW jump_node; +}; + +/** + * A Par represents parallel processing of all its children + */ +class KMPLAYER_NO_EXPORT Par : public GroupBase { +public: + KDE_NO_CDTOR_EXPORT Par (NodePtr & d) : GroupBase (d, id_node_par) {} + KDE_NO_EXPORT const char * nodeName () const { return "par"; } + void begin (); + void reset (); + void childDone (NodePtr child); +}; + +/** + * A Seq represents sequential processing of all its children + */ +class KMPLAYER_NO_EXPORT Seq : public GroupBase { +public: + KDE_NO_CDTOR_EXPORT Seq (NodePtr & d) : GroupBase(d, id_node_seq) {} + KDE_NO_EXPORT const char * nodeName () const { return "seq"; } + void begin (); + void childDone (NodePtr child); +protected: + KDE_NO_CDTOR_EXPORT Seq (NodePtr & d, short id) : GroupBase(d, id) {} +}; + +/** + * Represents the 'body' tag of SMIL document as in + * <smil><head/><body/></smil> + */ +class KMPLAYER_NO_EXPORT Body : public Seq { +public: + KDE_NO_CDTOR_EXPORT Body (NodePtr & d) : Seq (d, id_node_body) {} + KDE_NO_EXPORT const char * nodeName () const { return "body"; } +}; + +/** + * An Excl represents exclusive processing of one of its children + */ +class KMPLAYER_NO_EXPORT Excl : public GroupBase { +public: + KDE_NO_CDTOR_EXPORT Excl (NodePtr & d) : GroupBase (d, id_node_excl) {} + KDE_NO_EXPORT const char * nodeName () const { return "excl"; } + void begin (); + void deactivate (); + void childDone (NodePtr child); + virtual bool handleEvent (EventPtr event); +private: + typedef ListNode <ConnectionPtr> ConnectionStoreItem; + List <ConnectionStoreItem> started_event_list; +}; + +/* + * An automatic selection between child elements based on a condition + */ +class KMPLAYER_NO_EXPORT Switch : public GroupBase { +public: + KDE_NO_CDTOR_EXPORT Switch (NodePtr &d) : GroupBase (d, id_node_switch) {} + KDE_NO_EXPORT const char * nodeName () const { return "switch"; } + // Condition + void begin (); + void deactivate (); + void reset (); + void childDone (NodePtr child); + NodePtrW chosenOne; +}; + +class KMPLAYER_NO_EXPORT LinkingBase : public Element { +public: + KDE_NO_CDTOR_EXPORT ~LinkingBase () {} + void deactivate (); + KDE_NO_EXPORT bool expose () const { return false; } + void parseParam (const TrieString & name, const QString & value); + ConnectionPtr mediatype_activated; + ConnectionPtr mediatype_attach; + QString href; + enum { show_new, show_replace } show; +protected: + LinkingBase (NodePtr & d, short id); +}; + +class KMPLAYER_NO_EXPORT Anchor : public LinkingBase { +public: + Anchor (NodePtr & d); + KDE_NO_CDTOR_EXPORT ~Anchor () {} + void activate (); + void childDone (NodePtr child); + KDE_NO_EXPORT const char * nodeName () const { return "a"; } + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT void accept (Visitor * v) { v->visit (this); } +}; + +class KMPLAYER_NO_EXPORT Area : public LinkingBase { +public: + Area (NodePtr & d, const QString & tag); + ~Area (); + void activate (); + KDE_NO_EXPORT const char * nodeName () const { return tag.ascii (); } + KDE_NO_EXPORT void accept (Visitor * v) { v->visit (this); } + void parseParam (const TrieString & name, const QString & value); + NodeRefListPtr listeners (unsigned int event_id); + SizeType * coords; + int nr_coords; + const QString tag; + MouseListeners mouse_listeners; +}; + +/** + * Abstract base for the MediaType classes (video/audio/text/img/..) + */ +class KMPLAYER_NO_EXPORT MediaType : public TimedMrl { +public: + MediaType (NodePtr & d, const QString & t, short id); + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return m_type.latin1 (); } + void closed (); + void activate (); + void deactivate (); + void begin (); + void finish (); + void childDone (NodePtr child); + virtual SurfacePtr getSurface (NodePtr node); + /* (new) sub-region or NULL if not displayed */ + Surface *surface (); + void resetSurface (); + SRect calculateBounds (); + void boundsUpdate (); // recalculates and repaint old and new bounds + virtual void parseParam (const TrieString & name, const QString & value); + virtual bool handleEvent (EventPtr event); + NodeRefListPtr listeners (unsigned int event_id); + bool needsVideoWidget (); // for 'video' and 'ref' nodes + SurfacePtrW sub_surface; + NodePtrW external_tree; // if src points to playlist, the resolved top node + NodePtrW trans_in; + NodePtrW trans_out; + NodePtrW active_trans; + NodePtrW region_node; + QString m_type; + CalculatedSizer sizes; + Fit fit; + int opacity; + unsigned int bitrate; + unsigned int trans_step; + unsigned int trans_steps; + enum { sens_opaque, sens_transparent, sens_percentage } sensitivity; + bool trans_out_active; +protected: + MouseListeners mouse_listeners; + NodeRefListPtr m_MediaAttached; // mouse entered + ConnectionPtr region_paint; // attached region needs painting + ConnectionPtr region_mouse_enter; // attached region has mouse entered + ConnectionPtr region_mouse_leave; // attached region has mouse left + ConnectionPtr region_mouse_click; // attached region is clicked + ConnectionPtr region_attach; // attached to region + TimerInfoPtrW trans_timer; + TimerInfoPtrW trans_out_timer; +}; + +class KMPLAYER_NO_EXPORT AVMediaType : public MediaType { +public: + AVMediaType (NodePtr & d, const QString & t); + NodePtr childFromTag (const QString & tag); + virtual Runtime * getNewRuntime (); + virtual void defer (); + virtual void undefer (); + virtual void endOfFile (); + virtual void accept (Visitor *); + virtual bool expose () const; +}; + +class KMPLAYER_NO_EXPORT ImageMediaType : public MediaType { +public: + ImageMediaType (NodePtr & d); + Runtime * getNewRuntime (); + NodePtr childFromTag (const QString & tag); + PlayType playType () { return play_type_image; } + virtual void accept (Visitor *); +}; + +class KMPLAYER_NO_EXPORT TextMediaType : public MediaType { +public: + TextMediaType (NodePtr & d); + Runtime * getNewRuntime (); + PlayType playType () { return play_type_info; } + virtual void accept (Visitor *); +}; + +class KMPLAYER_NO_EXPORT RefMediaType : public MediaType { +public: + RefMediaType (NodePtr & d); + Runtime * getNewRuntime (); + virtual void accept (Visitor *); +}; + +class KMPLAYER_NO_EXPORT Brush : public MediaType { +public: + Brush (NodePtr & d); + virtual void accept (Visitor *); + virtual Runtime * getNewRuntime (); +}; + +class KMPLAYER_NO_EXPORT Set : public TimedMrl { +public: + KDE_NO_CDTOR_EXPORT Set (NodePtr & d) : TimedMrl (d, id_node_set) {} + KDE_NO_EXPORT const char * nodeName () const { return "set"; } + virtual Runtime * getNewRuntime (); + PlayType playType () { return play_type_none; } +}; + +class KMPLAYER_NO_EXPORT Animate : public TimedMrl { +public: + KDE_NO_CDTOR_EXPORT Animate (NodePtr & d) : TimedMrl (d, id_node_animate) {} + KDE_NO_EXPORT const char * nodeName () const { return "animate"; } + virtual Runtime * getNewRuntime (); + PlayType playType () { return play_type_none; } + bool handleEvent (EventPtr event); +}; + +class KMPLAYER_NO_EXPORT AnimateMotion : public TimedMrl { +public: + KDE_NO_CDTOR_EXPORT AnimateMotion (NodePtr & d) + : TimedMrl (d, id_node_animate) {} + KDE_NO_EXPORT const char * nodeName () const { return "animateMotion"; } + virtual Runtime *getNewRuntime (); + PlayType playType () { return play_type_none; } + bool handleEvent (EventPtr event); +}; + +// TODO animateColor transitionFilter + +class KMPLAYER_NO_EXPORT Param : public Element { +public: + KDE_NO_CDTOR_EXPORT Param (NodePtr & d) : Element (d, id_node_param) {} + KDE_NO_EXPORT const char * nodeName () const { return "param"; } + void activate (); + bool expose () const { return false; } +}; + +} // SMIL namespace + +} // KMPlayer namespace + +#endif //_KMPLAYER_SMIL_H_ diff --git a/src/kmplayer_xspf.cpp b/src/kmplayer_xspf.cpp new file mode 100644 index 0000000..c7fbce3 --- /dev/null +++ b/src/kmplayer_xspf.cpp @@ -0,0 +1,151 @@ +/** + * Copyright (C) 2006 by Koos Vriezen <[email protected]> + * + * 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 <config.h> +#include <kdebug.h> +#include <kurl.h> + +#include "kmplayer_xspf.h" + +using namespace KMPlayer; + + +KDE_NO_EXPORT NodePtr XSPF::Playlist::childFromTag (const QString & tag) { + const char * name = tag.latin1 (); + if (!strcasecmp (name, "tracklist")) + return new Tracklist (m_doc); + else if (!strcasecmp (name, "creator")) + return new DarkNode (m_doc, name, id_node_creator); + else if (!strcasecmp (name, "title")) + return new DarkNode (m_doc, name, id_node_title); + else if (!strcasecmp (name, "annotation")) + return new DarkNode (m_doc, name, id_node_annotation); + else if (!strcasecmp (name, "info")) + return new DarkNode (m_doc, name, id_node_info); + else if (!strcasecmp (name, "location")) + return new DarkNode (m_doc, name, id_node_location); + else if (!strcasecmp (name, "identifier")) + return new DarkNode (m_doc, name, id_node_identifier); + else if (!strcasecmp (name, "image")) + return new DarkNode (m_doc, name, id_node_image); + else if (!strcasecmp (name, "date")) + return new DarkNode (m_doc, name, id_node_date); + else if (!strcasecmp (name, "license")) + return new DarkNode (m_doc, name, id_node_license); + else if (!strcasecmp (name, "attribution")) + return new DarkNode (m_doc, name, id_node_attribution); + else if (!strcasecmp (name, "link")) + return new DarkNode (m_doc, name, id_node_link); + else if (!strcasecmp (name, "meta")) + return new DarkNode (m_doc, name, id_node_meta); + else if (!strcasecmp (name, "extension")) + return new DarkNode (m_doc, name, id_node_extension); + return 0L; +} + +KDE_NO_EXPORT void XSPF::Playlist::closed () { + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e->id == id_node_title) + pretty_name = e->innerText ().simplifyWhiteSpace (); + else if (e->id == id_node_location) + src = e->innerText ().stripWhiteSpace (); + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT NodePtr XSPF::Tracklist::childFromTag (const QString & tag) { + const char * name = tag.latin1 (); + if (!strcasecmp (name, "track")) + return new XSPF::Track (m_doc); + return 0L; +} + +//----------------------------------------------------------------------------- + +KDE_NO_EXPORT NodePtr XSPF::Track::childFromTag (const QString & tag) { + const char * name = tag.latin1 (); + if (!strcasecmp (name, "location")) + return new Location (m_doc); + else if (!strcasecmp (name, "creator")) + return new DarkNode (m_doc, name, id_node_creator); + else if (!strcasecmp (name, "title")) + return new DarkNode (m_doc, name, id_node_title); + else if (!strcasecmp (name, "annotation")) + return new DarkNode (m_doc, name, id_node_annotation); + else if (!strcasecmp (name, "info")) + return new DarkNode (m_doc, name, id_node_info); + else if (!strcasecmp (name, "identifier")) + return new DarkNode (m_doc, name, id_node_identifier); + else if (!strcasecmp (name, "album")) + return new DarkNode (m_doc, name, id_node_album); + else if (!strcasecmp (name, "image")) + return new DarkNode (m_doc, name, id_node_image); + else if (!strcasecmp (name, "trackNum")) + return new DarkNode (m_doc, name, id_node_tracknum); + else if (!strcasecmp (name, "duration")) + return new DarkNode (m_doc, name, id_node_duration); + else if (!strcasecmp (name, "link")) + return new DarkNode (m_doc, name, id_node_link); + else if (!strcasecmp (name, "meta")) + return new DarkNode (m_doc, name, id_node_meta); + else if (!strcasecmp (name, "extension")) + return new DarkNode (m_doc, name, id_node_extension); + return 0L; +} + +KDE_NO_EXPORT void XSPF::Track::closed () { + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + switch (e->id) { + case id_node_title: + pretty_name = e->innerText (); + break; + case id_node_location: + location = e; + src = e->mrl ()->src; + break; + } + } +} + +KDE_NO_EXPORT void XSPF::Track::activate () { + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->id == id_node_annotation) { + PlayListNotify * n = document ()->notify_listener; + if (n) + n->setInfoMessage (e->innerText ().stripWhiteSpace ()); + break; + } + Mrl::activate (); +} + +KDE_NO_EXPORT Node::PlayType XSPF::Track::playType () { + if (location) + return location->playType (); + return Mrl::playType (); +} + +KDE_NO_EXPORT Mrl * XSPF::Track::linkNode () { + if (location) + return location->mrl (); + return Mrl::linkNode (); +} + +void XSPF::Location::closed () { + src = innerText ().stripWhiteSpace (); +} diff --git a/src/kmplayer_xspf.h b/src/kmplayer_xspf.h new file mode 100644 index 0000000..83463e0 --- /dev/null +++ b/src/kmplayer_xspf.h @@ -0,0 +1,94 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2006 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYER_XSPF_H_ +#define _KMPLAYER_XSPF_H_ + +#include <qstring.h> + +#include "kmplayerplaylist.h" + +namespace KMPlayer { + +namespace XSPF { + +const short id_node_playlist = 500; +const short id_node_title = 501; +const short id_node_creator = 502; +const short id_node_annotation = 503; +const short id_node_info = 504; +const short id_node_location = 505; +const short id_node_identifier = 506; +const short id_node_image = 507; +const short id_node_date = 508; +const short id_node_license = 509; +const short id_node_attribution = 510; +const short id_node_meta = 511; +const short id_node_extension = 512; +const short id_node_tracklist = 513; +const short id_node_track = 514; +const short id_node_album = 515; +const short id_node_tracknum = 516; +const short id_node_duration = 517; +const short id_node_link = 518; + +class KMPLAYER_NO_EXPORT Playlist : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Playlist (NodePtr & d) : Mrl (d, id_node_playlist) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "playlist"; } + bool expose () const { return !pretty_name.isEmpty (); } + void closed (); +}; + +class KMPLAYER_NO_EXPORT Tracklist : public Element { +public: + KDE_NO_CDTOR_EXPORT Tracklist (NodePtr & d) : Element (d, id_node_tracklist) {} + NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "tracklist"; } + bool expose () const { return false; } +}; + +class KMPLAYER_NO_EXPORT Track : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Track (NodePtr & d) : Mrl (d, id_node_track) {} + void closed (); + void activate (); + PlayType playType (); + Mrl * linkNode (); + KDE_NO_EXPORT const char * nodeName () const { return "track"; } + NodePtr childFromTag (const QString & tag); + NodePtrW location; +}; + +class KMPLAYER_NO_EXPORT Location : public Mrl { +public: + KDE_NO_CDTOR_EXPORT Location (NodePtr &d) : Mrl (d, id_node_location) {} + KDE_NO_EXPORT const char * nodeName () const { return "location"; } + void closed (); + bool expose () const { return false; } +}; + +} //namespace XSPF + + +} // namespace KMPlayer + +#endif //_KMPLAYER_XSPF_H_ diff --git a/src/kmplayerapp.cpp b/src/kmplayerapp.cpp new file mode 100644 index 0000000..91e01a8 --- /dev/null +++ b/src/kmplayerapp.cpp @@ -0,0 +1,2296 @@ +/*************************************************************************** + kmplayerapp.cpp - description + ------------------- + begin : Sat Dec 7 16:14:51 CET 2002 + copyright : (C) 2002 by Koos Vriezen + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#undef Always + +// include files for QT +#include <qdatastream.h> +#include <qregexp.h> +#include <qiodevice.h> +#include <qprinter.h> +#include <qcursor.h> +#include <qpainter.h> +#include <qcheckbox.h> +#include <qpushbutton.h> +#include <qkeysequence.h> +#include <qapplication.h> +#include <qslider.h> +#include <qlayout.h> +#include <qwhatsthis.h> +#include <qtimer.h> +#include <qfile.h> +#include <qmetaobject.h> + +// include files for KDE +#include <kdeversion.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <klineeditdlg.h> +#include <kmenubar.h> +#include <kstatusbar.h> +#include <kurldrag.h> +#include <klocale.h> +#include <kconfig.h> +#include <kstdaction.h> +#include <kdebug.h> +#include <dcopclient.h> +#include <kpopupmenu.h> +#include <kurlrequester.h> +#include <klineedit.h> +#include <kkeydialog.h> +#include <ksystemtray.h> +#include <kedittoolbar.h> + +// application specific includes +#include "kmplayer.h" +#include "kmplayerview.h" +#include "playlistview.h" +#include "viewarea.h" +#include "kmplayercontrolpanel.h" +#include "kmplayerpartbase.h" +#include "kmplayerprocess.h" +#include "kmplayerappsource.h" +#include "kmplayertvsource.h" +#include "kmplayerbroadcast.h" +#include "kmplayervdr.h" +#include "kmplayerconfig.h" + +static const int DVDNav_start = 1; +static const int DVDNav_previous = 2; +static const int DVDNav_next = 3; +static const int DVDNav_root = 4; +static const int DVDNav_up = 5; + +extern const char * strMPlayerGroup; + +static const short id_node_recent_document = 31; +static const short id_node_recent_node = 32; +static const short id_node_disk_document = 33; +static const short id_node_disk_node = 34; + + +class KMPLAYER_NO_EXPORT ListsSource : public KMPlayer::URLSource { +public: + KDE_NO_CDTOR_EXPORT ListsSource (KMPlayer::PartBase * p) + : KMPlayer::URLSource (p, "lists://") {} + void jump (KMPlayer::NodePtr e); + void activate (); + void setDocument (KMPlayer::NodePtr doc, KMPlayer::NodePtr cur); + QString prettyName () { return m_document->mrl ()->pretty_name; } +}; + +class KMPLAYER_NO_EXPORT Recents : public FileDocument { +public: + Recents (KMPlayerApp *a); + void defer (); + void activate (); + void childDone (KMPlayer::NodePtr); + KMPlayer::NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "playlist"; } + KMPlayerApp * app; +}; + +class KMPLAYER_NO_EXPORT Recent : public KMPlayer::Mrl { +public: + Recent (KMPlayer::NodePtr & doc, KMPlayerApp *a, const QString &url = QString()); + void activate (); + void closed (); + KDE_NO_EXPORT const char * nodeName () const { return "item"; } + KMPlayerApp * app; +}; + +class KMPLAYER_NO_EXPORT Group : public KMPlayer::Mrl { +public: + Group (KMPlayer::NodePtr &doc, KMPlayerApp *a, const QString &pn=QString()); + KMPlayer::NodePtr childFromTag (const QString & tag); + void defer () {} // TODO lazy loading of largish sub trees + void closed (); + KDE_NO_EXPORT const char * nodeName () const { return "group"; } + KMPlayerApp * app; +}; + +class KMPLAYER_NO_EXPORT Playlist : public FileDocument { +public: + Playlist (KMPlayerApp *a, KMPlayer::PlayListNotify *n, bool plmod = false); + void childDone (KMPlayer::NodePtr); + void defer (); + void activate (); + KMPlayer::NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "playlist"; } + KMPlayerApp * app; + bool playmode; +}; + +class KMPLAYER_NO_EXPORT PlaylistItemBase : public KMPlayer::Mrl { +public: + PlaylistItemBase (KMPlayer::NodePtr &d, short id, KMPlayerApp *a, bool pm); + void activate (); + void closed (); + KMPlayerApp * app; + bool playmode; +}; + +class KMPLAYER_NO_EXPORT PlaylistItem : public PlaylistItemBase { +public: + PlaylistItem (KMPlayer::NodePtr & doc, KMPlayerApp *a, bool playmode, const QString &url = QString()); + void closed (); + void begin (); + PlayType playType () { return play_type_unknown; } + void setNodeName (const QString &); + const char * nodeName () const KDE_NO_EXPORT { return "item"; } +}; + +class KMPLAYER_NO_EXPORT PlaylistGroup : public KMPlayer::Mrl { +public: + PlaylistGroup (KMPlayer::NodePtr &doc, KMPlayerApp *a, const QString &pn); + PlaylistGroup (KMPlayer::NodePtr &doc, KMPlayerApp *a, bool plmode=false); + KMPlayer::NodePtr childFromTag (const QString & tag); + void closed (); + void setNodeName (const QString &); + KDE_NO_EXPORT const char * nodeName () const { return "group"; } + KMPlayerApp * app; + bool playmode; +}; + +class KMPLAYER_NO_EXPORT HtmlObject : public PlaylistItemBase { +public: + HtmlObject (KMPlayer::NodePtr & doc, KMPlayerApp *a, bool playmode); + void activate (); + void closed (); + KMPlayer::NodePtr childFromTag (const QString & tag); + const char * nodeName () const KDE_NO_EXPORT { return "object"; } +}; + +KDE_NO_EXPORT void ListsSource::jump (KMPlayer::NodePtr e) { + if (e->document()->firstChild ()) + Source::jump (e); + else + e->activate (); +} + +KDE_NO_EXPORT void ListsSource::activate () { + playCurrent (); +} + +KDE_NO_EXPORT void ListsSource::setDocument (KMPlayer::NodePtr doc, KMPlayer::NodePtr cur) { + if (m_document) + m_document->document()->dispose (); + m_document = doc; + m_current = cur; + //kdDebug () << "setDocument: " << m_document->outerXML () << endl; +} + +KDE_NO_CDTOR_EXPORT FileDocument::FileDocument (short i, const QString &s, KMPlayer::PlayListNotify * n) + : KMPlayer::Document (s, n) { + id = i; +} + +KDE_NO_EXPORT KMPlayer::NodePtr FileDocument::childFromTag(const QString &tag) { + if (tag == QString::fromLatin1 (nodeName ())) + return this; + return 0L; +} + +void FileDocument::readFromFile (const QString & fn) { + QFile file (fn); + kdDebug () << "readFromFile " << fn << endl; + if (file.exists ()) { + file.open (IO_ReadOnly); + QTextStream inxml (&file); + KMPlayer::readXML (this, inxml, QString (), false); + normalize (); + } +} + +void FileDocument::writeToFile (const QString & fn) { + QFile file (fn); + kdDebug () << "writeToFile " << fn << endl; + file.open (IO_WriteOnly); + QCString utf = outerXML ().utf8 (); + file.writeBlock (utf, utf.length ()); +} + +KDE_NO_CDTOR_EXPORT Recents::Recents (KMPlayerApp *a) + : FileDocument (id_node_recent_document, "recents://"), + app(a) { + pretty_name = i18n ("Most Recent"); +} + +KDE_NO_EXPORT void Recents::activate () { + if (!resolved) + defer (); +} + +KDE_NO_EXPORT void Recents::defer () { + if (!resolved) { + resolved = true; + readFromFile (locateLocal ("data", "kmplayer/recent.xml")); + } +} + +KDE_NO_EXPORT KMPlayer::NodePtr Recents::childFromTag (const QString & tag) { + // kdDebug () << nodeName () << " childFromTag " << tag << endl; + if (tag == QString::fromLatin1 ("item")) + return new Recent (m_doc, app); + else if (tag == QString::fromLatin1 ("group")) + return new Group (m_doc, app); + return FileDocument::childFromTag (tag); +} + +KDE_NO_EXPORT void Recents::childDone (KMPlayer::NodePtr) { + finish (); +} + +KDE_NO_CDTOR_EXPORT +Recent::Recent (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString &url) + : KMPlayer::Mrl (doc, id_node_recent_node), app (a) { + src = url; + setAttribute (KMPlayer::StringPool::attr_url, url); +} + +KDE_NO_EXPORT void Recent::closed () { + if (src.isEmpty ()) + src = getAttribute (KMPlayer::StringPool::attr_url); +} + +KDE_NO_EXPORT void Recent::activate () { + app->openDocumentFile (KURL (src)); +} + +KDE_NO_CDTOR_EXPORT +Group::Group (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString & pn) + : KMPlayer::Mrl (doc, KMPlayer::id_node_group_node), app (a) { + pretty_name = pn; + if (!pn.isEmpty ()) + setAttribute (KMPlayer::StringPool::attr_title, pn); +} + +KDE_NO_EXPORT KMPlayer::NodePtr Group::childFromTag (const QString & tag) { + if (tag == QString::fromLatin1 ("item")) + return new Recent (m_doc, app); + else if (tag == QString::fromLatin1 ("group")) + return new Group (m_doc, app); + return 0L; +} + +KDE_NO_EXPORT void Group::closed () { + if (pretty_name.isEmpty ()) + pretty_name = getAttribute (KMPlayer::StringPool::attr_title); +} + +KDE_NO_EXPORT void Playlist::defer () { + if (playmode) + KMPlayer::Document::defer (); + else if (!resolved) { + resolved = true; + readFromFile (locateLocal ("data", "kmplayer/playlist.xml")); + } +} + +KDE_NO_EXPORT void Playlist::activate () { + if (playmode) + KMPlayer::Document::activate (); + else if (!resolved) + defer (); +} + +KDE_NO_CDTOR_EXPORT Playlist::Playlist (KMPlayerApp *a, KMPlayer::PlayListNotify *n, bool plmode) + : FileDocument (KMPlayer::id_node_playlist_document, "Playlist://", n), + app(a), + playmode (plmode) { + pretty_name = i18n ("Persistent Playlists"); +} + +KDE_NO_EXPORT KMPlayer::NodePtr Playlist::childFromTag (const QString & tag) { + // kdDebug () << nodeName () << " childFromTag " << tag << endl; + const char * name = tag.ascii (); + if (!strcmp (name, "item")) + return new PlaylistItem (m_doc, app, playmode); + else if (!strcmp (name, "group")) + return new PlaylistGroup (m_doc, app, playmode); + else if (!strcmp (name, "object")) + return new HtmlObject (m_doc, app, playmode); + return FileDocument::childFromTag (tag); +} + +KDE_NO_EXPORT void Playlist::childDone (KMPlayer::NodePtr c) { + if (!playmode) + finish (); + else + FileDocument::childDone (c); +} + +KDE_NO_CDTOR_EXPORT +PlaylistItemBase::PlaylistItemBase (KMPlayer::NodePtr &d, short i, KMPlayerApp *a, bool pm) + : KMPlayer::Mrl (d, i), app (a), playmode (pm) { +} + +KDE_NO_EXPORT void PlaylistItemBase::activate () { + if (playmode) { + Mrl::activate (); + } else { + ListsSource * source = static_cast <ListsSource *> (app->player ()->sources () ["listssource"]); + KMPlayer::NodePtr pl = new Playlist (app, source, true); + QString data; + QString pn; + if (parentNode ()->id == KMPlayer::id_node_group_node) { + data = parentNode ()->innerXML (); + pn = parentNode ()->mrl ()->pretty_name; + } else { + data = outerXML (); + pn = pretty_name.isEmpty () ? src : pretty_name; + } + pl->mrl ()->pretty_name = pn; + //kdDebug () << "cloning to " << data << endl; + QTextStream inxml (data, IO_ReadOnly); + KMPlayer::readXML (pl, inxml, QString (), false); + pl->normalize (); + KMPlayer::NodePtr cur = pl->firstChild (); + pl->mrl ()->resolved = !!cur; + if (parentNode ()->id == KMPlayer::id_node_group_node && cur) { + KMPlayer::NodePtr sister = parentNode ()->firstChild (); + while (sister && cur && sister.ptr () != this) { + sister = sister->nextSibling (); + cur = cur->nextSibling (); + } + } + bool reset_only = source == app->player ()->source (); + if (reset_only) + app->player ()->stop (); + source->setDocument (pl, cur); + if (reset_only) { + source->activate (); + app->setCaption (pn); + } else + app->player ()->setSource (source); + } +} + +void PlaylistItemBase::closed () { + if (pretty_name.isEmpty ()) + pretty_name = getAttribute (KMPlayer::StringPool::attr_title); +} + +KDE_NO_CDTOR_EXPORT +PlaylistItem::PlaylistItem (KMPlayer::NodePtr & doc, KMPlayerApp *a, bool pm, const QString &url) + : PlaylistItemBase (doc, KMPlayer::id_node_playlist_item, a, pm) { + src = url; + setAttribute (KMPlayer::StringPool::attr_url, url); +} + +KDE_NO_EXPORT void PlaylistItem::closed () { + if (src.isEmpty ()) + src = getAttribute (KMPlayer::StringPool::attr_url); + PlaylistItemBase::closed (); +} + +KDE_NO_EXPORT void PlaylistItem::begin () { + if (playmode && firstChild ()) + firstChild ()->activate (); + else + Mrl::begin (); +} + +KDE_NO_EXPORT void PlaylistItem::setNodeName (const QString & s) { + src = s; + setAttribute (KMPlayer::StringPool::attr_url, s); +} + +KDE_NO_CDTOR_EXPORT +PlaylistGroup::PlaylistGroup (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString & pn) + : KMPlayer::Mrl (doc, KMPlayer::id_node_group_node), app (a), playmode (false) { + pretty_name = pn; + if (!pn.isEmpty ()) + setAttribute (KMPlayer::StringPool::attr_title, pn); +} + +KDE_NO_CDTOR_EXPORT +PlaylistGroup::PlaylistGroup (KMPlayer::NodePtr & doc, KMPlayerApp * a, bool lm) + : KMPlayer::Mrl (doc, KMPlayer::id_node_group_node), app (a), playmode (lm) { +} + +KDE_NO_EXPORT KMPlayer::NodePtr PlaylistGroup::childFromTag (const QString & tag) { + const char * name = tag.ascii (); + if (!strcmp (name, "item")) + return new PlaylistItem (m_doc, app, playmode); + else if (!strcmp (name, "group")) + return new PlaylistGroup (m_doc, app, playmode); + else if (!strcmp (name, "object")) + return new HtmlObject (m_doc, app, playmode); + return 0L; +} + +KDE_NO_EXPORT void PlaylistGroup::closed () { + if (pretty_name.isEmpty ()) + pretty_name = getAttribute (KMPlayer::StringPool::attr_title); +} + +KDE_NO_EXPORT void PlaylistGroup::setNodeName (const QString & t) { + pretty_name = t; + setAttribute (KMPlayer::StringPool::attr_title, t); +} + +KDE_NO_CDTOR_EXPORT +HtmlObject::HtmlObject (KMPlayer::NodePtr &doc, KMPlayerApp *a, bool pm) + : PlaylistItemBase (doc, KMPlayer::id_node_html_object, a, pm) {} + +KDE_NO_EXPORT void HtmlObject::activate () { + if (playmode) + KMPlayer::Mrl::activate (); + else + PlaylistItemBase::activate (); +} + +KDE_NO_EXPORT void HtmlObject::closed () { + for (Node *n = firstChild ().ptr (); n; n = n->nextSibling ().ptr ()) { + if (n->id == KMPlayer::id_node_param) { + KMPlayer::Element *e = static_cast <KMPlayer::Element *> (n); + QString name = e->getAttribute (KMPlayer::StringPool::attr_name); + if (name == "type") + mimetype = e->getAttribute (KMPlayer::StringPool::attr_value); + else if (name == "movie") + src = e->getAttribute (KMPlayer::StringPool::attr_value); + } else if (n->id == KMPlayer::id_node_html_embed) { + KMPlayer::Element *e = static_cast <KMPlayer::Element *> (n); + QString type = e->getAttribute (KMPlayer::StringPool::attr_type); + if (!type.isEmpty ()) + mimetype = type; + QString asrc = e->getAttribute (KMPlayer::StringPool::attr_src); + if (!asrc.isEmpty ()) + src = asrc; + } + } + PlaylistItemBase::closed (); +} + +KDE_NO_EXPORT KMPlayer::NodePtr HtmlObject::childFromTag (const QString & tag) { + const char *name = tag.ascii (); + if (!strcasecmp (name, "param")) + return new KMPlayer::DarkNode (m_doc, name, KMPlayer::id_node_param); + else if (!strcasecmp (name, "embed")) + return new KMPlayer::DarkNode(m_doc, name,KMPlayer::id_node_html_embed); + return NULL; +} + +KDE_NO_CDTOR_EXPORT KMPlayerApp::KMPlayerApp(QWidget* , const char* name) + : KMainWindow(0, name), + config (kapp->config ()), + m_systray (0L), + m_player (new KMPlayer::PartBase (this, 0L, 0L, 0L, config)), + m_view (static_cast <KMPlayer::View*> (m_player->view())), + m_dvdmenu (new QPopupMenu (this)), + m_dvdnavmenu (new QPopupMenu (this)), + m_vcdmenu (new QPopupMenu (this)), + m_audiocdmenu (new QPopupMenu (this)), + m_tvmenu (new QPopupMenu (this)), + m_ffserverconfig (new KMPlayerFFServerConfig), + m_broadcastconfig (new KMPlayerBroadcastConfig (m_player, m_ffserverconfig)), + edit_tree_id (-1), + last_time_left (0), + m_played_intro (false), + m_played_exit (false), + m_minimal_mode (false) +{ + setCentralWidget (m_view); + connect (m_broadcastconfig, SIGNAL (broadcastStarted()), this, SLOT (broadcastStarted())); + connect (m_broadcastconfig, SIGNAL (broadcastStopped()), this, SLOT (broadcastStopped())); + initStatusBar(); +#ifdef HAVE_DBUS + m_player->setServiceName (QString ("org.kde.kmplayer-%1").arg (getpid ())); +#endif + m_player->init (actionCollection ()); + m_player->players () ["xvideo"] = new XVideo(m_player,m_player->settings()); + m_player->setProcess ("mplayer"); + m_player->setRecorder ("mencoder"); + ListsSource * lstsrc = new ListsSource (m_player); + m_player->sources () ["listssource"] = lstsrc; + m_player->sources () ["dvdsource"] = new ::KMPlayerDVDSource(this, m_dvdmenu); + m_player->sources () ["dvdnavsource"] = new KMPlayerDVDNavSource (this, m_dvdnavmenu); + m_player->sources () ["vcdsource"] = new KMPlayerVCDSource(this, m_vcdmenu); + m_player->sources () ["audiocdsource"] = new KMPlayerAudioCDSource (this, m_audiocdmenu); + m_player->sources () ["pipesource"] = new KMPlayerPipeSource (this); + m_player->sources () ["tvsource"] = new KMPlayerTVSource (this, m_tvmenu); + m_player->sources () ["vdrsource"] = new KMPlayerVDRSource (this); + m_player->setSource (m_player->sources () ["urlsource"]); + initActions(); + initView(); + + //setAutoSaveSettings(); + playlist = new Playlist (this, lstsrc); + playlist_id = m_view->playList ()->addTree (playlist, "listssource", "player_playlist", KMPlayer::PlayListView::AllowDrag | KMPlayer::PlayListView::AllowDrops | KMPlayer::PlayListView::TreeEdit | KMPlayer::PlayListView::Moveable | KMPlayer::PlayListView::Deleteable); + readOptions(); +} + +KDE_NO_CDTOR_EXPORT KMPlayerApp::~KMPlayerApp () { + delete m_broadcastconfig; + if (recents) + recents->document ()->dispose (); + if (playlist) + playlist->document ()->dispose (); +} + + +KDE_NO_EXPORT void KMPlayerApp::initActions () { + KActionCollection * ac = actionCollection (); + fileNewWindow = new KAction(i18n("New &Window"), 0, 0, this, SLOT(slotFileNewWindow()), ac, "new_window"); + fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), ac, "open"); + fileOpenRecent = KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), ac, "open_recent"); + KStdAction::saveAs (this, SLOT (slotSaveAs ()), ac, "save_as"); + new KAction (i18n ("Clear &History"), 0, 0, this, SLOT (slotClearHistory ()), ac, "clear_history"); + fileClose = KStdAction::close (this, SLOT (slotFileClose ()), ac); + fileQuit = KStdAction::quit (this, SLOT (slotFileQuit ()), ac); + new KAction (i18n ("&Open DVD"), QString ("dvd_mount"), KShortcut (), this, SLOT(openDVD ()), ac, "opendvd"); + new KAction (i18n ("&Open VCD"), QString ("cdrom_mount"), KShortcut (), this, SLOT(openVCD ()), ac, "openvcd"); + new KAction (i18n ("&Open Audio CD"), QString ("cdrom_mount"), KShortcut (), this, SLOT(openAudioCD ()), ac, "openaudiocd"); + new KAction (i18n ("&Open Pipe..."), QString ("pipe"), KShortcut (), this, SLOT(openPipe ()), ac, "source_pipe"); + //KGlobal::iconLoader ()->loadIconSet (QString ("tv"), KIcon::Small, 0,true) + new KAction (i18n ("&Connect"), QString ("connect_established"), KShortcut (), this, SLOT (openVDR ()), ac, "vdr_connect"); + editVolumeInc = new KAction (i18n ("Increase Volume"), QString ("player_volume"), KShortcut (), m_player, SLOT (increaseVolume ()), ac, "edit_volume_up"); + editVolumeDec = new KAction (i18n ("Decrease Volume"), QString ("player_volume"), KShortcut (), m_player, SLOT(decreaseVolume ()), ac, "edit_volume_down"); + toggleView = new KAction (i18n ("C&onsole"), QString ("konsole"), KShortcut (), m_player->view(), SLOT (toggleVideoConsoleWindow ()), ac, "view_video"); + //new KAction (i18n ("V&ideo"), QString ("video"), KShortcut (), m_view, SLOT (toggleVideoConsoleWindow ()), ac, "view_video"); + new KAction (i18n ("Pla&y List"), QString ("player_playlist"), KShortcut (), m_player, SLOT (showPlayListWindow ()), ac, "view_playlist"); + new KAction (i18n ("Minimal mode"), QString ("empty"), KShortcut (), this, SLOT (slotMinimalMode ()), ac, "view_minimal"); + new KAction (i18n ("50%"), 0, 0, this, SLOT (zoom50 ()), ac, "view_zoom_50"); + new KAction (i18n ("100%"), QString ("viewmagfit"), KShortcut (), this, SLOT (zoom100 ()), ac, "view_zoom_100"); + new KAction (i18n ("150%"), 0, 0, this, SLOT (zoom150 ()), ac, "view_zoom_150"); + viewEditMode = new KToggleAction (i18n ("&Edit mode"), 0, 0, this, SLOT (editMode ()), ac, "edit_mode"); + viewSyncEditMode = new KAction (i18n ("Sync &with playlist"), QString ("reload"), KShortcut (), this, SLOT (syncEditMode ()), ac, "sync_edit_mode"); + viewSyncEditMode->setEnabled (false); + new KAction (i18n ("Show Popup Menu"), KShortcut (), m_view->controlPanel (), SLOT (showPopupMenu ()), ac, "view_show_popup_menu"); + new KAction (i18n ("Show Language Menu"), KShortcut (Qt::Key_L), m_view->controlPanel (), SLOT (showLanguageMenu ()), ac, "view_show_lang_menu"); + viewKeepRatio = new KToggleAction (i18n ("&Keep Width/Height Ratio"), 0, this, SLOT (keepSizeRatio ()), ac, "view_keep_ratio"); +#if KDE_IS_VERSION(3,1,90) + viewFullscreen = KStdAction::fullScreen (this, SLOT(fullScreen ()), ac, 0, "view_fullscreen"); +#else + viewFullscreen = new KAction (i18n("&Full Screen"), 0, 0, this, SLOT(fullScreen ()), ac, "view_fullscreen"); +#endif + /*KAction *playact =*/ new KAction (i18n ("P&lay"), QString ("player_play"), KShortcut (), m_player, SLOT (play ()), ac, "play"); + /*KAction *pauseact =*/ new KAction (i18n ("&Pause"), QString ("player_pause"), KShortcut (), m_player, SLOT (pause ()), ac, "pause"); + /*KAction *stopact =*/ new KAction (i18n ("&Stop"), QString ("player_stop"), KShortcut (), m_player, SLOT (stop ()), ac, "stop"); + /*KAction *artsctrl =*/ new KAction (i18n ("&Arts Control"), QString ("player_volume"), KShortcut (), this, SLOT (startArtsControl ()), ac, "view_arts_control"); + viewToolBar = KStdAction::showToolbar(this, SLOT(slotViewToolBar()), ac, "showtoolbar"); + viewStatusBar =KStdAction::showStatusbar(this,SLOT(slotViewStatusBar()),ac, "showstatusbar"); + viewMenuBar = KStdAction::showMenubar(this, SLOT(slotViewMenuBar()), ac, "showmenu"); + KStdAction::preferences(m_player, SLOT(showConfigDialog()), ac,"configure"); + fileNewWindow->setStatusText(i18n("Opens a new application window")); + fileOpen->setStatusText(i18n("Opens an existing file")); + fileOpenRecent->setStatusText(i18n("Opens a recently used file")); + fileClose->setStatusText(i18n("Closes the actual source")); + fileQuit->setStatusText(i18n("Quits the application")); + //viewToolBar->setStatusText(i18n("Enables/disables the toolbar")); + viewStatusBar->setStatusText(i18n("Enables/disables the statusbar")); + viewMenuBar->setStatusText(i18n("Enables/disables the menubar")); + KStdAction::keyBindings( this, SLOT(slotConfigureKeys()), ac, "configkeys"); + KStdAction::configureToolbars (this, SLOT (slotConfigureToolbars ()), ac, "configtoolbars"); +} + +KDE_NO_EXPORT void KMPlayerApp::initStatusBar () { + KStatusBar *sb = statusBar (); + sb->insertItem (i18n ("Ready."), id_status_msg); + sb->insertItem (QString ("--:--"), id_status_timer, 0, true); +} + +KDE_NO_EXPORT void KMPlayerApp::initMenu () { + createGUI (); // first build the one from the kmplayerui.rc + QPopupMenu * bookmarkmenu = m_view->controlPanel()->bookmarkMenu (); + m_view->controlPanel()->popupMenu ()->removeItem (KMPlayer::ControlPanel::menu_bookmark); + menuBar ()->insertItem (i18n ("&Bookmarks"), bookmarkmenu, -1, 2); + m_sourcemenu = menuBar ()->findItem (menuBar ()->idAt (0)); + m_sourcemenu->setText (i18n ("S&ource")); + m_sourcemenu->popup ()->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("dvd_mount"), KIcon::Small, 0, true), i18n ("&DVD"), m_dvdmenu, -1, 5); + m_dvdmenu->clear (); +#ifdef HAVE_XINE + m_dvdnavmenu->clear (); + m_dvdnavmenu->insertItem (i18n ("&Start"), this, SLOT (dvdNav ())); + m_dvdmenu->insertItem (i18n ("&DVD Navigator"), m_dvdnavmenu, -1, 1); + m_dvdmenu->insertItem (i18n ("&Open DVD"), this, SLOT(openDVD ()), 0,-1, 2); +#else + m_dvdmenu->insertItem (i18n ("&Open DVD"), this, SLOT(openDVD ()), 0,-1, 1); +#endif + m_sourcemenu->popup ()->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("cdrom_mount"), KIcon::Small, 0, true), i18n ("V&CD"), m_vcdmenu, -1, 6); + m_vcdmenu->clear (); + m_sourcemenu->popup ()->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("tv"), KIcon::Small, 0, true), i18n ("&TV"), m_tvmenu, -1, 8); + m_vcdmenu->insertItem (i18n ("&Open VCD"), this, SLOT(openVCD ()), 0,-1, 1); + m_sourcemenu->popup ()->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("cdrom_mount"), KIcon::Small, 0, true), i18n ("&Audio CD"), m_audiocdmenu, -1, 7); + m_audiocdmenu->insertItem (i18n ("&Open Audio CD"), this, SLOT(openAudioCD ()), 0,-1, 1); +} + +KDE_NO_EXPORT void KMPlayerApp::initView () { + //m_view->docArea ()->readDockConfig (config, QString ("Window Layout")); + m_player->connectPanel (m_view->controlPanel ()); + initMenu (); + new KAction (i18n ("Increase Volume"), editVolumeInc->shortcut (), m_player, SLOT (increaseVolume ()), m_view->viewArea ()->actionCollection (), "edit_volume_up"); + new KAction (i18n ("Decrease Volume"), editVolumeDec->shortcut (), m_player, SLOT(decreaseVolume ()), m_view->viewArea ()->actionCollection (), "edit_volume_down"); + connect (m_player->settings (), SIGNAL (configChanged ()), + this, SLOT (configChanged ())); + connect (m_player, SIGNAL (loading (int)), + this, SLOT (loadingProgress (int))); + connect (m_player, SIGNAL (positioned (int, int)), + this, SLOT (positioned (int, int))); + connect (m_player, SIGNAL (statusUpdated (const QString &)), + this, SLOT (slotStatusMsg (const QString &))); + connect (m_view, SIGNAL (windowVideoConsoleToggled (int)), + this, SLOT (windowVideoConsoleToggled (int))); + connect (m_player, SIGNAL (sourceChanged (KMPlayer::Source *, KMPlayer::Source *)), this, SLOT (slotSourceChanged(KMPlayer::Source *, KMPlayer::Source *))); + m_view->controlPanel ()->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom50, + this, SLOT (zoom50 ())); + m_view->controlPanel ()->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom100, + this, SLOT (zoom100 ())); + m_view->controlPanel ()->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom150, + this, SLOT (zoom150 ())); + connect (m_view->controlPanel()->broadcastButton (), SIGNAL (clicked ()), + this, SLOT (broadcastClicked ())); + m_auto_resize = m_player->settings ()->autoresize; + if (m_auto_resize) + connect (m_player, SIGNAL (sourceDimensionChanged ()), + this, SLOT (zoom100 ())); + connect (m_view, SIGNAL (fullScreenChanged ()), + this, SLOT (fullScreen ())); + connect (m_view->playList (), SIGNAL (selectionChanged (QListViewItem *)), + this, SLOT (playListItemSelected (QListViewItem *))); + connect (m_view->playList(), SIGNAL (dropped (QDropEvent*, QListViewItem*)), + this, SLOT (playListItemDropped (QDropEvent *, QListViewItem *))); + connect (m_view->playList(), SIGNAL (moved ()), + this, SLOT (playListItemMoved ())); + connect (m_view->playList(), SIGNAL (prepareMenu (KMPlayer::PlayListItem *, QPopupMenu *)), this, SLOT (preparePlaylistMenu (KMPlayer::PlayListItem *, QPopupMenu *))); + m_dropmenu = new QPopupMenu (m_view->playList ()); + m_dropmenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("player_playlist"), KIcon::Small, 0, true), i18n ("&Add to list"), this, SLOT (menuDropInList ())); + m_dropmenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("folder_grey"), KIcon::Small, 0, true), i18n ("Add in new &Group"), this, SLOT (menuDropInGroup ())); + m_dropmenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("editcopy"), KIcon::Small, 0, true), i18n ("&Copy here"), this, SLOT (menuCopyDrop ())); + m_dropmenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("editdelete"), KIcon::Small, 0, true), i18n ("&Delete"), this, SLOT (menuDeleteNode ())); + /*QPopupMenu * viewmenu = new QPopupMenu; + viewmenu->insertItem (i18n ("Full Screen"), this, SLOT(fullScreen ()), + QKeySequence ("CTRL + Key_F")); + menuBar ()->insertItem (i18n ("&View"), viewmenu, -1, 2);*/ + //toolBar("mainToolBar")->hide(); + setAcceptDrops (true); +} + +KDE_NO_EXPORT void KMPlayerApp::loadingProgress (int perc) { + if (perc < 100) + statusBar ()->changeItem (QString ("%1%").arg (perc), id_status_timer); + else + statusBar ()->changeItem (QString ("--:--"), id_status_timer); +} + +KDE_NO_EXPORT void KMPlayerApp::positioned (int pos, int length) { + int left = (length - pos) / 10; + if (left != last_time_left) { + last_time_left = left; + QString text ("--:--"); + if (left > 0) { + int h = left / 3600; + int m = (left % 3600) / 60; + int s = left % 60; + if (h > 0) + text.sprintf ("%d:%02d:%02d", h, m, s); + else + text.sprintf ("%02d:%02d", m, s); + } + statusBar ()->changeItem (text, id_status_timer); + } +} + +KDE_NO_EXPORT void KMPlayerApp::windowVideoConsoleToggled (int wt) { + if (wt == int (KMPlayer::View::WT_Video)) { + toggleView->setText (i18n ("C&onsole")); + toggleView->setIcon (QString ("konsole")); + } else { + toggleView->setText (i18n ("V&ideo")); + toggleView->setIcon (QString ("video")); + } +} + +KDE_NO_EXPORT void KMPlayerApp::playerStarted () { + KMPlayer::Source * source = m_player->source (); + if (!strcmp (source->name (), "urlsource")) { + KURL url = source->url (); + if (url.url ().startsWith ("lists")) + return; + if (url.isEmpty () && m_player->process ()->mrl ()) + url = KURL (m_player->process ()->mrl ()->mrl ()->src); + recentFiles ()->addURL (url); + recents->defer (); // make sure it's loaded + recents->insertBefore (new Recent (recents, this, url.url ()), recents->firstChild ()); + KMPlayer::NodePtr c = recents->firstChild ()->nextSibling (); + int count = 1; + KMPlayer::NodePtr more; + while (c) { + if (c->id == id_node_recent_node && + c->mrl ()->src == url.url ()) { + KMPlayer::NodePtr tmp = c->nextSibling (); + recents->removeChild (c); + c = tmp; + } else { + if (c->id == KMPlayer::id_node_group_node) + more = c; + c = c->nextSibling (); + count++; + } + } + if (!more && count > 10) { + more = new Group (recents, this, i18n ("More...")); + recents->appendChild (more); + } + if (more) { + KMPlayer::NodePtr item; + if (count > 10) { + KMPlayer::NodePtr item = more->previousSibling (); + recents->removeChild (item); + more->insertBefore (item, more->firstChild ()); + } + if (more->firstChild ()) + c = more->firstChild ()->nextSibling (); + count = 0; + while (c) { + if (c->id == id_node_recent_node && + c->mrl ()->src == url.url ()) { + KMPlayer::NodePtr tmp = c->nextSibling (); + more->removeChild (c); + c = tmp; + } else { + c = c->nextSibling (); + count++; + } + } + if (count > 50) + more->removeChild (more->lastChild ()); + } + m_view->playList ()->updateTree (recents_id, recents, 0, false, false); + } +} + +KDE_NO_EXPORT void KMPlayerApp::slotSourceChanged (KMPlayer::Source *olds, KMPlayer::Source * news) { + if (olds) { + disconnect (olds, SIGNAL (titleChanged (const QString &)), this, + SLOT (setCaption (const QString &))); + disconnect (olds, SIGNAL (startPlaying ()), + this, SLOT (playerStarted ())); + } + if (news) { + setCaption (news->prettyName (), false); + connect (news, SIGNAL (titleChanged (const QString &)), + this, SLOT (setCaption (const QString &))); + connect (news, SIGNAL (startPlaying ()), + this, SLOT (playerStarted ())); + viewSyncEditMode->setEnabled (m_view->editMode () || + !strcmp (m_player->source ()->name (), "urlsource")); + } +} + +KDE_NO_EXPORT void KMPlayerApp::dvdNav () { + slotStatusMsg(i18n("DVD Navigation...")); + m_player->setSource (m_player->sources () ["dvdnavsource"]); + slotStatusMsg(i18n("Ready")); +} + +KDE_NO_EXPORT void KMPlayerApp::openDVD () { + slotStatusMsg(i18n("Opening DVD...")); + m_player->setSource (m_player->sources () ["dvdsource"]); +} + +KDE_NO_EXPORT void KMPlayerApp::openVCD () { + slotStatusMsg(i18n("Opening VCD...")); + m_player->setSource (m_player->sources () ["vcdsource"]); +} + +KDE_NO_EXPORT void KMPlayerApp::openAudioCD () { + slotStatusMsg(i18n("Opening Audio CD...")); + m_player->setSource (m_player->sources () ["audiocdsource"]); +} + +KDE_NO_EXPORT void KMPlayerApp::openPipe () { + slotStatusMsg(i18n("Opening pipe...")); + bool ok; + QString cmd = KLineEditDlg::getText (i18n("Read From Pipe"), + i18n ("Enter a command that will output an audio/video stream\nto the stdout. This will be piped to a player's stdin.\n\nCommand:"), m_player->sources () ["pipesource"]->pipeCmd (), &ok, m_player->view()); + if (!ok) { + slotStatusMsg (i18n ("Ready.")); + return; + } + static_cast <KMPlayerPipeSource *> (m_player->sources () ["pipesource"])->setCommand (cmd); + m_player->setSource (m_player->sources () ["pipesource"]); +} + +KDE_NO_EXPORT void KMPlayerApp::openVDR () { + slotStatusMsg(i18n("Opening VDR...")); + if (!strcmp (m_player->source ()->name (), "vdrsource") && m_player->process ()->playing ()) + static_cast<KMPlayerVDRSource *>(m_player->source())->toggleConnected(); + else + m_player->setSource (m_player->sources () ["vdrsource"]); +} + +#ifdef HAVE_CAIRO +struct IntroSource : public KMPlayer::Source { + KMPlayerApp * m_app; + IntroSource (KMPlayer::PartBase *p, KMPlayerApp * a) + : KMPlayer::Source (i18n ("Intro"), p, "introsource"), m_app (a) {} + KDE_NO_EXPORT bool hasLength () { return false; } + KDE_NO_EXPORT bool isSeekable () { return false; } + KDE_NO_EXPORT QString prettyName () { return i18n ("Intro"); } + void activate (); + void deactivate (); + void stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State os, KMPlayer::Node::State ns); + bool deactivated; + bool finished; +}; + +KDE_NO_EXPORT void IntroSource::activate () { + if (m_player->settings ()->autoresize) + m_app->disconnect(m_player, SIGNAL(sourceDimensionChanged()),m_app,SLOT(zoom100())); + m_document = new KMPlayer::Document (QString (""), this); + QString introfile = locate ("data", "kmplayer/intro.xml"); + QFile file (introfile); + if (file.exists () && file.open (IO_ReadOnly)) { + QTextStream ts (&file); + KMPlayer::readXML (m_document, ts, QString (), false); + } else { + QString smil = QString::fromLatin1 ( + "<smil><head><layout>" + "<root-layout width='320' height='240' background-color='black'/>" + "<region id='image1' left='31.25%' top='25%' width='37.5%' height='50%' z-order='1'/>" + "<region id='reg1' top='10%' height='80%' z-order='2'>" + "<region id='image2' left='128' top='72' width='64' bottom='56'/>" + "</region>" + "</layout>" + "<transition id='fadein-1' dur='0.6' type='fade'/>" + "<transition id='iris1' dur='0.3' type='irisWipe'/>" + "</head>" + "<body>" + "<excl>" + "<par>" + "<img src='%1' region='image1' dur='.6' fit='fill' transOut='iris1'/>" + "<img region='image2' src='%2' begin='0.3' dur='0.6' fit='hidden' fill='freeze' transIn='fadein-1'/>" + "</par>" + "<seq begin='reg1.activateEvent'/>" + "</excl>" + "</body></smil>" + ).arg (locate ("data", "kmplayer/noise.gif")).arg (KGlobal::iconLoader()->iconPath (QString::fromLatin1 ("kmplayer"), -64)); + QTextStream ts (smil.utf8 (), IO_ReadOnly); + KMPlayer::readXML (m_document, ts, QString (), false); + } + //m_document->normalize (); + m_current = m_document; //mrl->self (); + if (m_document && m_document->firstChild ()) { + KMPlayer::Mrl * mrl = m_document->firstChild ()->mrl (); + if (mrl) { + Source::setDimensions (m_document->firstChild (), mrl->width, mrl->height); + m_player->updateTree (); + m_current->activate (); + emit startPlaying (); + } + } + deactivated = finished = false; +} + +KDE_NO_EXPORT void IntroSource::stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State, KMPlayer::Node::State new_state) { + if (new_state == KMPlayer::Node::state_deactivated && + m_document == node) { + m_document->reset (); + finished = true; + if (m_player->view ()) + m_app->restoreFromConfig (); + emit stopPlaying (); + if (!deactivated) // replace introsource with urlsource + m_player->openURL (KURL ()); + } +} + +KDE_NO_EXPORT void IntroSource::deactivate () { + deactivated = true; + if (m_player->settings ()->autoresize) + m_app->connect(m_player, SIGNAL(sourceDimensionChanged()),m_app,SLOT(zoom100())); + if (!finished && m_document) // user opens a source while introducing + m_document->reset (); +} +#endif + +KDE_NO_EXPORT void KMPlayerApp::restoreFromConfig () { + if (m_player->view ()) { + m_view->docArea ()->hide (); + m_view->docArea ()->readDockConfig (m_player->config (), QString ("Window Layout")); + m_view->docArea ()->show (); + m_view->layout ()->activate (); + } +} + +KDE_NO_EXPORT void KMPlayerApp::openDocumentFile (const KURL& url) +{ + if (!m_played_intro) { + m_played_intro = true; + KMPlayer::Source * src = m_player->sources () ["urlsource"]; + if (url.isEmpty () && src->document () && + src->document ()->hasChildNodes ()) { + restoreFromConfig (); + m_player->setSource (src); + return; +#ifdef HAVE_CAIRO + } else if (!m_player->settings ()->no_intro && url.isEmpty ()) { + m_player->setSource (new IntroSource (m_player, this)); + return; +#endif + } else { + m_played_exit = true; // no intro, so no exit as well + restoreFromConfig (); + } + } + slotStatusMsg(i18n("Opening file...")); + m_player->openURL (url); + if (m_broadcastconfig->broadcasting () && url.url() == m_broadcastconfig->serverURL ()) { + // speed up replay + FFServerSetting & ffs = m_broadcastconfig->ffserversettings; + KMPlayer::Source * source = m_player->source (); + if (!ffs.width.isEmpty () && !ffs.height.isEmpty ()) { + source->setWidth (ffs.width.toInt ()); + source->setHeight (ffs.height.toInt ()); + } + source->setIdentified (); + } + slotStatusMsg (i18n ("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerApp::addURL (const KURL& url) { + KMPlayer::Source * src = m_player->sources () ["urlsource"]; + KMPlayer::NodePtr d = src->document (); + if (d) + d->appendChild (new KMPlayer::GenericURL (d, url.url ())); +} + +KDE_NO_EXPORT void KMPlayerApp::saveProperties (KConfig * config) { + config->writeEntry ("URL", m_player->source ()->url ().url ()); + config->writeEntry ("Visible", isVisible ()); +} + +KDE_NO_EXPORT void KMPlayerApp::readProperties (KConfig * config) { + KURL url (config->readEntry ("URL", QString ())); + openDocumentFile (url); + if (!config->readBoolEntry ("Visible", true) && m_systray) + hide (); +} + +KDE_NO_EXPORT void KMPlayerApp::resizePlayer (int percentage) { + KMPlayer::Source * source = m_player->source (); + if (!source) + return; + int w, h; + source->dimensions (w, h); + if (w == 0 && h == 0) { + w = 320; + h = 240; + } else + h = m_view->viewer ()->heightForWidth (w); + //kdDebug () << "KMPlayerApp::resizePlayer (" << w << "," << h << ")" << endl; + if (w > 0 && h > 0) { + if (m_view->controlPanel ()->isVisible ()) + h += m_view->controlPanel ()->size ().height (); + QSize s1 = size (); + QSize s2 = m_view->viewArea ()->size (); + w += s1.width () - s2.width (); + h += s1.height () - s2.height (); + w = int (1.0 * w * percentage/100.0); + h = int (1.0 * h * percentage/100.0); + QSize s = sizeForCentralWidgetSize (QSize (w, h)); + if (s.width () != width () || s.height () != height ()) { + QSize oldsize = m_view->viewArea ()->size (); + resize (s); + } + } +} + +KDE_NO_EXPORT void KMPlayerApp::zoom50 () { + resizePlayer (50); +} + +KDE_NO_EXPORT void KMPlayerApp::zoom100 () { + resizePlayer (100); +} + +KDE_NO_EXPORT void KMPlayerApp::zoom150 () { + resizePlayer (150); +} + +KDE_NO_EXPORT void KMPlayerApp::editMode () { + m_view->docArea ()->hide (); + bool editmode = !m_view->editMode (); + KMPlayer::PlayListItem * pi = m_view->playList ()->currentPlayListItem (); + if (!pi || !pi->node) + editmode = false; + m_view->docArea ()->show (); + viewEditMode->setChecked (editmode); + KMPlayer::RootPlayListItem * ri = (edit_tree_id > 0 && !editmode) + ? m_view->playList ()->rootItem (edit_tree_id) + : m_view->playList ()->rootItem (pi); + if (editmode) { + edit_tree_id = ri->id; + m_view->setEditMode (ri, true); + m_view->setInfoMessage (pi->node->innerXML ()); + viewSyncEditMode->setEnabled (true); + } else { + m_view->setEditMode (ri, false); + edit_tree_id = -1; + viewSyncEditMode->setEnabled (!strcmp (m_player->source ()->name (), "urlsource")); + } +} + +KDE_NO_EXPORT void KMPlayerApp::syncEditMode () { + if (edit_tree_id > -1) { + KMPlayer::PlayListItem *si = m_view->playList()->selectedPlayListItem(); + if (si && si->node) { + si->node->clearChildren (); + QString txt = m_view->infoPanel ()->text (); + QTextStream ts (txt, IO_ReadOnly); + KMPlayer::readXML (si->node, ts, QString (), false); + m_view->playList ()->updateTree (edit_tree_id, si->node->document(), si->node, true, false); + } + } else + m_player->openURL (m_player->source ()->url ()); +} + +KDE_NO_EXPORT void KMPlayerApp::showBroadcastConfig () { + m_player->settings ()->addPage (m_broadcastconfig); + m_player->settings ()->addPage (m_ffserverconfig); +} + +KDE_NO_EXPORT void KMPlayerApp::hideBroadcastConfig () { + m_player->settings ()->removePage (m_broadcastconfig); + m_player->settings ()->removePage (m_ffserverconfig); +} + +KDE_NO_EXPORT void KMPlayerApp::broadcastClicked () { + if (m_broadcastconfig->broadcasting ()) + m_broadcastconfig->stopServer (); + else { + m_player->settings ()->show ("BroadcastPage"); + m_view->controlPanel()->broadcastButton ()->toggle (); + } +} + +KDE_NO_EXPORT void KMPlayerApp::broadcastStarted () { + if (!m_view->controlPanel()->broadcastButton ()->isOn ()) + m_view->controlPanel()->broadcastButton ()->toggle (); +} + +KDE_NO_EXPORT void KMPlayerApp::broadcastStopped () { + if (m_view->controlPanel()->broadcastButton ()->isOn ()) + m_view->controlPanel()->broadcastButton ()->toggle (); + if (m_player->source () != m_player->sources () ["tvsource"]) + m_view->controlPanel()->broadcastButton ()->hide (); + setCursor (QCursor (Qt::ArrowCursor)); +} + +KDE_NO_EXPORT bool KMPlayerApp::broadcasting () const { + return m_broadcastconfig->broadcasting (); +} + +KDE_NO_EXPORT void KMPlayerApp::saveOptions() +{ + config->setGroup ("General Options"); + if (m_player->settings ()->remembersize) + config->writeEntry ("Geometry", size()); + config->writeEntry ("Show Toolbar", viewToolBar->isChecked()); + config->writeEntry ("ToolBarPos", (int) toolBar("mainToolBar")->barPos()); + config->writeEntry ("Show Statusbar",viewStatusBar->isChecked()); + config->writeEntry ("Show Menubar",viewMenuBar->isChecked()); + if (!m_player->sources () ["pipesource"]->pipeCmd ().isEmpty ()) { + config->setGroup ("Pipe Command"); + config->writeEntry ("Command1", m_player->sources () ["pipesource"]->pipeCmd ()); + } + m_view->setInfoMessage (QString ()); + m_view->docArea ()->writeDockConfig (config, QString ("Window Layout")); + Recents * rc = static_cast <Recents *> (recents.ptr ()); + if (rc && rc->resolved) { + fileOpenRecent->saveEntries (config,"Recent Files"); + rc->writeToFile (locateLocal ("data", "kmplayer/recent.xml")); + } + Playlist * pl = static_cast <Playlist *> (playlist.ptr ()); + if (pl && pl->resolved) + pl->writeToFile (locateLocal ("data", "kmplayer/playlist.xml")); +} + + +KDE_NO_EXPORT void KMPlayerApp::readOptions() { + + config->setGroup("General Options"); + + // bar position settings + KToolBar::BarPosition toolBarPos; + toolBarPos=(KToolBar::BarPosition) config->readNumEntry("ToolBarPos", KToolBar::Top); + toolBar("mainToolBar")->setBarPos(toolBarPos); + + // bar status settings + viewToolBar->setChecked (config->readBoolEntry("Show Toolbar", true)); + slotViewToolBar(); + + bool bViewStatusbar = config->readBoolEntry("Show Statusbar", true); + viewStatusBar->setChecked(bViewStatusbar); + slotViewStatusBar(); + + viewMenuBar->setChecked (config->readBoolEntry("Show Menubar", true)); + slotViewMenuBar(); + + QSize size = config->readSizeEntry ("Geometry"); + if (!size.isEmpty ()) + resize (size); + else if (m_player->settings ()->remembersize) + resize (QSize (640, 480)); + + config->setGroup ("Pipe Command"); + static_cast <KMPlayerPipeSource *> (m_player->sources () ["pipesource"])->setCommand (config->readEntry ("Command1", "")); + // initialize the recent file list + if (!recents) { + fileOpenRecent->loadEntries(config,"Recent Files"); + recents = new Recents (this); + recents_id = m_view->playList ()->addTree (recents, "listssource", "history", KMPlayer::PlayListView::AllowDrag); + } + configChanged (); +} + +#include <netwm.h> +#undef Always +#undef Never +#undef Status +#undef Unsorted +#undef Bool + +KDE_NO_EXPORT void KMPlayerApp::minimalMode (bool by_user) { + unsigned long props = NET::WMWindowType; + NETWinInfo winfo (qt_xdisplay (), winId (), qt_xrootwin (), props); + if (m_minimal_mode) { + winfo.setWindowType (NET::Normal); + readOptions (); + if (by_user) + disconnect (m_view->controlPanel ()->button (KMPlayer::ControlPanel::button_playlist), SIGNAL (clicked ()), this, SLOT (slotMinimalMode ())); + restoreFromConfig (); + } else { + saveOptions (); + menuBar()->hide(); + toolBar("mainToolBar")->hide(); + statusBar()->hide(); + if (by_user) + connect (m_view->controlPanel ()->button (KMPlayer::ControlPanel::button_playlist), SIGNAL (clicked ()), this, SLOT (slotMinimalMode ())); + if (by_user) +#if KDE_IS_VERSION(3, 1, 90) + winfo.setWindowType (NET::Utility); +#else + winfo.setWindowType (NET::Menu); +#endif + } + m_view->viewArea ()->minimalMode (); + if (by_user) { + QRect rect = m_view->viewArea ()->topWindowRect (); + hide (); + QTimer::singleShot (0, this, SLOT (zoom100 ())); + show (); + move (rect.x (), rect.y ()); + } + m_minimal_mode = !m_minimal_mode; +} + +KDE_NO_EXPORT void KMPlayerApp::slotMinimalMode () { + minimalMode (true); +} + +#ifdef HAVE_CAIRO +struct ExitSource : public KMPlayer::Source { + KDE_NO_CDTOR_EXPORT ExitSource (KMPlayer::PartBase *p) + : KMPlayer::Source (i18n ("Exit"), p, "exitsource") {} + KDE_NO_EXPORT QString prettyName () { return i18n ("Exit"); } + KDE_NO_EXPORT bool hasLength () { return false; } + KDE_NO_EXPORT bool isSeekable () { return false; } + void activate (); + KDE_NO_EXPORT void deactivate () {} + void stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State os, KMPlayer::Node::State ns); +}; + +KDE_NO_EXPORT void ExitSource::activate () { + m_document = new KMPlayer::Document (QString (""), this); + QString exitfile = locate ("data", "kmplayer/exit.xml"); + QFile file (exitfile); + if (file.exists () && file.open (IO_ReadOnly)) { + QTextStream ts (&file); + KMPlayer::readXML (m_document, ts, QString (), false); + } else { + QString smil = QString::fromLatin1 ("<smil><head><layout>" + "<root-layout width='320' height='240' background-color='black'/>" + "<region id='reg1' top='10%' height='80%' z-order='2'>" + "<region id='image' left='128' top='72' width='64' bottom='56'/>" + "</region></layout>" + "<transition id='pw' dur='0.3' type='pushWipe' subtype='fromBottom'/>" + "</head><body>" + "<par>" + //"<animate target='reg1' attribute='background-color' calcMode='discrete' values='#FFFFFF;#E4E4E4;#CCCCCC;#B4B4B4;#9E9E9E;#8A8A8A;#777777;#656565;#555555;#464646;#393939;#2D2D2D;#222222;#191919;#111111;#0B0B0B;#060606;#020202;#000000;#000000' dur='0.6'/>" + "<img src='%2' id='img1' region='image' dur='0.4' fit='hidden' transOut='pw'/>" + "</par>" + "</body></smil>").arg (KGlobal::iconLoader()->iconPath (QString::fromLatin1 ("kmplayer"), -64)); + QTextStream ts (smil.utf8 (), IO_ReadOnly); + KMPlayer::readXML (m_document, ts, QString (), false); + } + //m_document->normalize (); + m_current = m_document; + if (m_document && m_document->firstChild ()) { + KMPlayer::Mrl * mrl = m_document->firstChild ()->mrl (); + if (mrl) { + setDimensions (m_document->firstChild (), mrl->width, mrl->height); + m_player->updateTree (); + m_current->activate (); + emit startPlaying (); + return; + } + } + qApp->quit (); +} + +KDE_NO_EXPORT void ExitSource::stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State, KMPlayer::Node::State new_state) { + if (new_state == KMPlayer::Node::state_deactivated && + m_document == node && + m_player->view ()) + m_player->view ()->topLevelWidget ()->close (); +} +#endif + +KDE_NO_EXPORT bool KMPlayerApp::queryClose () { + // KMPlayerVDRSource has to wait for pending commands like mute and quit + m_player->stop (); + static_cast <KMPlayerVDRSource *> (m_player->sources () ["vdrsource"])->waitForConnectionClose (); + // is arts control still running + if (!m_dcopName.isEmpty ()) { + QCString replytype; + QByteArray data, replydata; + kapp->dcopClient ()->call (m_dcopName, "MainApplication-Interface", "quit()", data, replytype, replydata); + } + if (m_played_exit || m_player->settings ()->no_intro || kapp->sessionSaving() ) + return true; + if (m_auto_resize) + disconnect(m_player, SIGNAL(sourceDimensionChanged()),this,SLOT(zoom100())); + m_played_exit = true; + if (!m_minimal_mode) + minimalMode (false); +#ifdef HAVE_CAIRO + m_player->setSource (new ExitSource (m_player)); + return false; +#else + return true; +#endif +} + +KDE_NO_EXPORT bool KMPlayerApp::queryExit() +{ + if (!m_minimal_mode) + saveOptions(); + disconnect (m_player->settings (), SIGNAL (configChanged ()), + this, SLOT (configChanged ())); + m_player->settings ()->writeConfig (); + return true; +} + +KDE_NO_EXPORT void KMPlayerApp::slotFileNewWindow() +{ + slotStatusMsg(i18n("Opening a new application window...")); + + KMPlayerApp *new_window= new KMPlayerApp(); + new_window->show(); + + slotStatusMsg(i18n("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerApp::slotFileOpen () { + KURL::List urls = KFileDialog::getOpenURLs (QString (), i18n ("*|All Files"), this, i18n ("Open File")); + if (urls.size () == 1) { + openDocumentFile (urls [0]); + } else if (urls.size () > 1) { + m_player->openURL (KURL ()); + for (unsigned int i = 0; i < urls.size (); i++) + addURL (urls [i]); + } +} + +KDE_NO_EXPORT void KMPlayerApp::slotFileOpenRecent(const KURL& url) +{ + slotStatusMsg(i18n("Opening file...")); + + openDocumentFile (url); + +} + +KDE_NO_EXPORT void KMPlayerApp::slotSaveAs () { + QString url = KFileDialog::getSaveFileName (QString (), QString (), this, i18n ("Save File")); + if (!url.isEmpty ()) { + QFile file (url); + if (!file.open (IO_WriteOnly)) { + KMessageBox::error (this, i18n ("Error opening file %1.\n%2.").arg (url).arg (file.errorString ()), i18n("Error")); + return; + } + if (m_player->source ()) { + KMPlayer::NodePtr doc = m_player->source ()->document (); + if (doc) { + QTextStream ts (&file); + ts.setEncoding (QTextStream::UnicodeUTF8); + ts << QString ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + if (doc->childNodes ()->length () == 1) + ts << doc->innerXML (); + else + ts << doc->outerXML (); + } + } + file.close (); + } +} + +KDE_NO_EXPORT void KMPlayerApp::slotClearHistory () { + //fileOpenRecent->clearURLList (); + int mi = fileOpenRecent->maxItems (); + fileOpenRecent->setMaxItems (0); + fileOpenRecent->setMaxItems (mi); + m_player->settings ()->urllist.clear (); + m_player->settings ()->sub_urllist.clear (); + if (recents) { // small window this check fails and thus ClearHistory fails + recents->defer (); // make sure it's loaded + recents->clear (); + m_view->playList ()->updateTree (recents_id, recents, 0, false, false); + } +} + +KDE_NO_EXPORT void KMPlayerApp::slotFileClose() +{ + slotStatusMsg(i18n("Closing file...")); + + m_player->stop (); + + slotStatusMsg(i18n("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerApp::slotFileQuit() +{ + slotStatusMsg(i18n("Exiting...")); + + // whoever implemented this should fix it too, work around .. + if (memberList->count () > 1) + deleteLater (); + else + qApp->quit (); + // close the first window, the list makes the next one the first again. + // This ensures that queryClose() is called on each window to ask for closing + /*KMainWindow* w; + if(memberList) + { + for(w=memberList->first(); w!=0; w=memberList->first()) + { + // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog, + // the window and the application stay open. + if(!w->close()) + break; + } + }*/ +} + +KDE_NO_EXPORT void KMPlayerApp::slotPreferences () { + m_player->showConfigDialog (); +} + +KDE_NO_EXPORT void KMPlayerApp::slotConfigureKeys () { + KKeyDialog::configure( actionCollection(), this ); +} + +KDE_NO_EXPORT void KMPlayerApp::slotConfigureToolbars () { + KEditToolbar dlg (actionCollection ()); + if (dlg.exec ()) + initMenu (); // also add custom popups //createGUI (); +} + +KDE_NO_EXPORT void KMPlayerApp::slotViewToolBar() { + m_showToolbar = viewToolBar->isChecked(); + if(m_showToolbar) + toolBar("mainToolBar")->show(); + else + toolBar("mainToolBar")->hide(); +} + +KDE_NO_EXPORT void KMPlayerApp::slotViewStatusBar() { + m_showStatusbar = viewStatusBar->isChecked(); + if(m_showStatusbar) + statusBar()->show(); + else + statusBar()->hide(); +} + +KDE_NO_EXPORT void KMPlayerApp::slotViewMenuBar() { + m_showMenubar = viewMenuBar->isChecked(); + if (m_showMenubar) { + menuBar()->show(); + slotStatusMsg(i18n("Ready")); + } else { + menuBar()->hide(); + slotStatusMsg (i18n ("Show Menubar with %1").arg(viewMenuBar->shortcutText())); + if (!m_showStatusbar) { + statusBar()->show(); + QTimer::singleShot (3000, statusBar(), SLOT (hide ())); + } + } +} + +KDE_NO_EXPORT void KMPlayerApp::slotStatusMsg (const QString &text) { + KStatusBar * sb = statusBar (); + sb->clear (); + sb->changeItem (text, id_status_msg); +} + +KDE_NO_EXPORT void KMPlayerApp::fullScreen () { + if (sender ()->metaObject ()->inherits ("KAction")) + m_view->fullScreen(); +#if KDE_IS_VERSION(3,1,90) + viewFullscreen->setChecked (m_view->isFullScreen ()); +#endif + if (m_view->isFullScreen()) + hide (); + else { + show (); + setGeometry (m_view->viewArea ()->topWindowRect ()); + } +} + +KDE_NO_EXPORT void KMPlayerApp::playListItemSelected (QListViewItem * item) { + KMPlayer::PlayListItem * vi = static_cast <KMPlayer::PlayListItem *> (item); + if (edit_tree_id > -1) { + if (vi->playListView ()->rootItem (item)->id != edit_tree_id) + editMode (); + m_view->setInfoMessage (edit_tree_id > -1 ? vi->node->innerXML () : QString ()); + } + viewEditMode->setEnabled (vi->playListView ()->rootItem (item)->flags & KMPlayer::PlayListView::TreeEdit); +} + +KDE_NO_EXPORT +void KMPlayerApp::playListItemDropped (QDropEvent * de, QListViewItem * after) { + if (!after) { // could still be a descendent + after = m_view->playList()->itemAt (m_view->playList()->contentsToViewport (de->pos ())); + if (after) { + QListViewItem * p = after->itemAbove (); + if (p && p->nextSibling () != after) + after = after->parent (); + } + } + if (!after) + return; + KMPlayer::RootPlayListItem *ritem = m_view->playList()->rootItem(after); + if (ritem->id == 0) + return; + manip_node = 0L; + m_drop_list.clear (); + m_drop_after = after; + KMPlayer::NodePtr after_node = static_cast<KMPlayer::PlayListItem*> (after)->node; + if (after_node->id == KMPlayer::id_node_playlist_document || + after_node->id == KMPlayer::id_node_group_node) + after_node->defer (); // make sure it has loaded + if (de->source () == m_view->playList() && + m_view->playList()->lastDragTreeId () == playlist_id) + manip_node = m_view->playList()->lastDragNode (); + if (!manip_node && ritem->id == playlist_id) { + if (KURLDrag::canDecode (de)) { + KURLDrag::decode (de, m_drop_list); + } else if (QTextDrag::canDecode (de)) { + QString text; + QTextDrag::decode (de, text); + m_drop_list.push_back (KURL (text)); + } + } + m_dropmenu->changeItem (m_dropmenu->idAt (0), + !!manip_node ? i18n ("Move here") : i18n ("&Add to list")); + m_dropmenu->setItemVisible (m_dropmenu->idAt (3), !!manip_node); + m_dropmenu->setItemVisible (m_dropmenu->idAt (2), (manip_node && manip_node->isPlayable ())); + if (manip_node || m_drop_list.size () > 0) + m_dropmenu->exec (m_view->playList ()->mapToGlobal (m_view->playList ()->contentsToViewport (de->pos ()))); +} + +KDE_NO_EXPORT void KMPlayerApp::menuDropInList () { + KMPlayer::NodePtr n = static_cast<KMPlayer::PlayListItem*>(m_drop_after)->node; + KMPlayer::NodePtr pi; + for (int i = m_drop_list.size (); n && (i > 0 || manip_node); i--) { + if (manip_node && manip_node->parentNode ()) { + pi = manip_node; + manip_node = 0L; + pi->parentNode ()->removeChild (pi); + } else + pi = new PlaylistItem(playlist, this,false, m_drop_list[i-1].url()); + if (n == playlist || m_drop_after->isOpen ()) + n->insertBefore (pi, n->firstChild ()); + else + n->parentNode ()->insertBefore (pi, n->nextSibling ()); + } + m_view->playList()->updateTree (playlist_id, playlist, pi, true, false); +} + +KDE_NO_EXPORT void KMPlayerApp::menuDropInGroup () { + KMPlayer::NodePtr n = static_cast<KMPlayer::PlayListItem*>(m_drop_after)->node; + if (!n) + return; + KMPlayer::NodePtr g = new PlaylistGroup (playlist, this, i18n("New group")); + if (n == playlist || m_drop_after->isOpen ()) + n->insertBefore (g, n->firstChild ()); + else + n->parentNode ()->insertBefore (g, n->nextSibling ()); + KMPlayer::NodePtr pi; + for (int i = 0; i < m_drop_list.size () || manip_node; ++i) { + if (manip_node && manip_node->parentNode ()) { + pi = manip_node; + manip_node = 0L; + pi->parentNode ()->removeChild (pi); + } else + pi = new PlaylistItem (playlist,this, false, m_drop_list[i].url ()); + g->appendChild (pi); + } + m_view->playList()->updateTree (playlist_id, playlist, pi, true, false); +} + +KDE_NO_EXPORT void KMPlayerApp::menuCopyDrop () { + KMPlayer::NodePtr n = static_cast<KMPlayer::PlayListItem*>(m_drop_after)->node; + if (n && manip_node) { + KMPlayer::NodePtr pi = new PlaylistItem (playlist, this, false, manip_node->mrl ()->src); + if (n == playlist || m_drop_after->isOpen ()) + n->insertBefore (pi, n->firstChild ()); + else + n->parentNode ()->insertBefore (pi, n->nextSibling ()); + m_view->playList()->updateTree (playlist_id, playlist, pi, true, false); + } +} + +KDE_NO_EXPORT void KMPlayerApp::menuDeleteNode () { + KMPlayer::NodePtr n; + if (manip_node && manip_node->parentNode ()) { + n = manip_node->previousSibling() ? manip_node->previousSibling() : manip_node->parentNode (); + manip_node->parentNode ()->removeChild (manip_node); + } + m_view->playList()->updateTree (manip_tree_id, 0L, n, true, false); +} + +KDE_NO_EXPORT void KMPlayerApp::menuMoveUpNode () { + KMPlayer::NodePtr n = manip_node; + if (n && n->parentNode () && n->previousSibling ()) { + KMPlayer::NodePtr prev = n->previousSibling (); + n->parentNode ()->removeChild (n); + prev->parentNode ()->insertBefore (n, prev); + } + m_view->playList()->updateTree (manip_tree_id, 0L, n, true, false); +} + +KDE_NO_EXPORT void KMPlayerApp::menuMoveDownNode () { + KMPlayer::NodePtr n = manip_node; + if (n && n->parentNode () && n->nextSibling ()) { + KMPlayer::NodePtr next = n->nextSibling (); + n->parentNode ()->removeChild (n); + next->parentNode ()->insertBefore (n, next->nextSibling ()); + } + m_view->playList()->updateTree (manip_tree_id, 0L, n, true, false); +} + +KDE_NO_EXPORT void KMPlayerApp::playListItemMoved () { + KMPlayer::PlayListItem * si = m_view->playList ()->selectedPlayListItem (); + KMPlayer::RootPlayListItem * ri = m_view->playList ()->rootItem (si); + kdDebug() << "playListItemMoved " << (ri->id == playlist_id) << !! si->node << endl; + if (ri->id == playlist_id && si->node) { + KMPlayer::NodePtr p = si->node->parentNode (); + if (p) { + p->removeChild (si->node); + m_view->playList()->updateTree(playlist_id,playlist,0L,false,false); + } + } +} + +KDE_NO_EXPORT void KMPlayerApp::preparePlaylistMenu (KMPlayer::PlayListItem * item, QPopupMenu * pm) { + KMPlayer::RootPlayListItem * ri = m_view->playList ()->rootItem (item); + if (item->node && + ri->flags & (KMPlayer::PlayListView::Moveable | KMPlayer::PlayListView::Deleteable)) { + manip_tree_id = ri->id; + pm->insertSeparator (); + manip_node = item->node; + if (ri->flags & KMPlayer::PlayListView::Deleteable) + pm->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("editdelete"), KIcon::Small, 0, true), i18n ("&Delete item"), this, SLOT (menuDeleteNode ())); + if (ri->flags & KMPlayer::PlayListView::Moveable) { + if (manip_node->previousSibling ()) + pm->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("up"), KIcon::Small, 0, true), i18n ("&Move up"), this, SLOT (menuMoveUpNode ())); + if (manip_node->nextSibling ()) + pm->insertItem (KGlobal::iconLoader()->loadIconSet (QString ("down"), KIcon::Small, 0, true), i18n ("Move &down"), this, SLOT (menuMoveDownNode ())); + } + } +} + + +KDE_NO_EXPORT void KMPlayerApp::startArtsControl () { + QCString fApp, fObj; + QByteArray data, replydata; + QCStringList apps = kapp->dcopClient ()->registeredApplications(); + QCStringList::ConstIterator end( apps.end() ); + for( QCStringList::ConstIterator it = apps.begin(); it != end; ++it) + if (!strncmp ((*it).data (), "artscontrol", 11)) { + kapp->dcopClient ()->findObject + (*it, "artscontrol-mainwindow#1", "raise()", data, fApp, fObj); + return; + } + QStringList args; + QCString replytype; + QDataStream stream (data, IO_WriteOnly); + stream << QString ("aRts Control Tool") << args; + if (kapp->dcopClient ()->call ("klauncher", "klauncher", "start_service_by_name(QString,QStringList)", data, replytype, replydata)) { + int result; + QDataStream replystream (replydata, IO_ReadOnly); + replystream >> result >> m_dcopName; + } +} + +KDE_NO_EXPORT void KMPlayerApp::configChanged () { + viewKeepRatio->setChecked (m_player->settings ()->sizeratio); + if (m_player->settings ()->docksystray && !m_systray) { + m_systray = new KSystemTray (this); + m_systray->setPixmap (KGlobal::iconLoader ()->loadIcon (QString ("kmplayer"), KIcon::NoGroup, 22)); + m_systray->show (); + } else if (!m_player->settings ()->docksystray && m_systray) { + delete m_systray; + m_systray = 0L; + } + if (m_player->settings ()->autoresize && !m_auto_resize) + connect(m_player,SIGNAL(sourceDimensionChanged()),this,SLOT(zoom100())); + else if (!m_player->settings ()->autoresize && m_auto_resize) + disconnect(m_player, SIGNAL(sourceDimensionChanged()),this,SLOT(zoom100())); + m_auto_resize = m_player->settings ()->autoresize; + static_cast <KMPlayerTVSource *> (m_player->sources () ["tvsource"])->buildMenu (); +} + +KDE_NO_EXPORT void KMPlayerApp::keepSizeRatio () { + m_view->setKeepSizeRatio (!m_view->keepSizeRatio ()); + m_player->settings ()->sizeratio = m_view->keepSizeRatio (); + viewKeepRatio->setChecked (m_view->keepSizeRatio ()); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerMenuSource::KMPlayerMenuSource (const QString & n, KMPlayerApp * a, QPopupMenu * m, const char * src) + : KMPlayer::Source (n, a->player (), src), m_menu (m), m_app (a) { +} + +KDE_NO_CDTOR_EXPORT KMPlayerMenuSource::~KMPlayerMenuSource () { +} + +KDE_NO_EXPORT void KMPlayerMenuSource::menuItemClicked (QPopupMenu * menu, int id) { + int unsetmenuid = -1; + for (unsigned i = 0; i < menu->count(); i++) { + int menuid = menu->idAt (i); + if (menu->isItemChecked (menuid)) { + menu->setItemChecked (menuid, false); + unsetmenuid = menuid; + break; + } + } + if (unsetmenuid != id) + menu->setItemChecked (id, true); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageDVD::KMPlayerPrefSourcePageDVD (QWidget * parent) + : QFrame(parent) { + QVBoxLayout *layout = new QVBoxLayout (this, 5, 2); + autoPlayDVD = new QCheckBox (i18n ("Auto play after opening DVD"), this, 0); + QWhatsThis::add(autoPlayDVD, i18n ("Start playing DVD right after opening DVD")); + QLabel *dvdDevicePathLabel = new QLabel (i18n("DVD device:"), this, 0); + dvddevice = new KURLRequester ("/dev/dvd", this, 0); + QWhatsThis::add(dvddevice, i18n ("Path to your DVD device, you must have read rights to this device")); + layout->addWidget (autoPlayDVD); + layout->addItem (new QSpacerItem (0, 10, QSizePolicy::Minimum, QSizePolicy::Minimum)); + layout->addWidget (dvdDevicePathLabel); + layout->addWidget (dvddevice); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +//----------------------------------------------------------------------------- + +class KMPLAYER_NO_EXPORT Disks : public KMPlayer::Document { +public: + Disks (KMPlayerApp * a); + void childDone (KMPlayer::NodePtr); + KMPlayerApp * app; +}; + +class KMPLAYER_NO_EXPORT Disk : public KMPlayer::Mrl { +public: + Disk (KMPlayer::NodePtr & doc, KMPlayerApp *a, const QString &url, const QString &pn); + void activate (); + KMPlayerApp * app; +}; + +KDE_NO_CDTOR_EXPORT Disks::Disks (KMPlayerApp * a) + : KMPlayer::Document ("disks://", 0L), app (a) { + id = id_node_disk_document; + pretty_name = i18n ("Optical Disks"); +} + +KDE_NO_EXPORT void Disks::childDone (KMPlayer::NodePtr) { + finish (); +} + +KDE_NO_CDTOR_EXPORT Disk::Disk (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString &url, const QString &pn) + : KMPlayer::Mrl (doc, id_node_disk_node), app (a) { + src = url; + pretty_name = pn; +} + +KDE_NO_EXPORT void Disk::activate () { + const char * sn; + if (src.startsWith ("cdda")) + sn = "audiocdsource"; + else if (src.startsWith ("vcd")) + sn = "vcdsource"; + else + sn = "dvdsource"; + app->player ()->setSource (app->player ()->sources () [sn]); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerDVDSource::KMPlayerDVDSource (KMPlayerApp * a, QPopupMenu * m) + : KMPlayerMenuSource (i18n ("DVD"), a, m, "dvdsource"), m_configpage (0L) { + m_menu->insertTearOffHandle (); + m_dvdtitlemenu = new QPopupMenu (m_app); + m_dvdsubtitlemenu = new QPopupMenu (m_app); + m_dvdchaptermenu = new QPopupMenu (m_app); + m_dvdlanguagemenu = new QPopupMenu (m_app); + m_dvdtitlemenu->setCheckable (true); + m_dvdsubtitlemenu->setCheckable (true); + m_dvdchaptermenu->setCheckable (true); + m_dvdlanguagemenu->setCheckable (true); + setURL (KURL ("dvd://")); + m_player->settings ()->addPage (this); + disks = new Disks (a); + disks->appendChild (new Disk (disks, a, "cdda://", i18n ("CDROM - Audio Compact Disk"))); + disks->appendChild (new Disk (disks, a, "vcd://", i18n ("VCD - Video Compact Disk"))); + disks->appendChild (new Disk (disks, a, "dvd://", i18n ("DVD - Digital Video Disk"))); + m_app->view()->playList()->addTree (disks, "listssource", "cdrom_mount", 0); +} + +KDE_NO_CDTOR_EXPORT KMPlayerDVDSource::~KMPlayerDVDSource () { + disks->document ()->dispose (); +} + +KDE_NO_EXPORT bool KMPlayerDVDSource::processOutput (const QString & str) { + if (KMPlayer::Source::processOutput (str)) + return true; + if (m_identified) + return false; + //kdDebug () << "scanning " << cstr << endl; + QRegExp * patterns = static_cast <KMPlayer::MPlayer *> (m_player->players () ["mplayer"])->configPage ()->m_patterns; + QRegExp & langRegExp = patterns[KMPlayer::MPlayerPreferencesPage::pat_dvdlang]; + QRegExp & subtitleRegExp = patterns[KMPlayer::MPlayerPreferencesPage::pat_dvdsub]; + QRegExp & titleRegExp = patterns[KMPlayer::MPlayerPreferencesPage::pat_dvdtitle]; + QRegExp & chapterRegExp = patterns[KMPlayer::MPlayerPreferencesPage::pat_dvdchapter]; + bool post090 = m_player->settings ()->mplayerpost090; + if (!post090 && subtitleRegExp.search (str) > -1) { + bool ok; + int sub_id = subtitleRegExp.cap (1).toInt (&ok); + QString sub_title = ok ? subtitleRegExp.cap (2) : subtitleRegExp.cap(1); + if (!ok) + sub_id = subtitleRegExp.cap (2).toInt (&ok); + m_dvdsubtitlemenu->insertItem (sub_title, sub_id); + kdDebug () << "subtitle sid:" << sub_id << " lang:" << sub_title <<endl; + } else if (!post090 && langRegExp.search (str) > -1) { + bool ok; + int lang_id = langRegExp.cap (1).toInt (&ok); + QString lang_title = ok ? langRegExp.cap (2) : langRegExp.cap (1); + if (!ok) + lang_id = langRegExp.cap (2).toInt (&ok); + m_dvdlanguagemenu->insertItem (lang_title, lang_id); + kdDebug () << "lang aid:" << lang_id << " lang:" << lang_title << endl; + } else if (titleRegExp.search (str) > -1) { + kdDebug () << "title " << titleRegExp.cap (1) << endl; + unsigned ts = titleRegExp.cap (1).toInt (); + if ( ts > 100) ts = 100; + for (unsigned t = 1; t <= ts; t++) + m_dvdtitlemenu->insertItem (QString::number (t), t); + } else if (chapterRegExp.search (str) > -1) { + kdDebug () << "chapter " << chapterRegExp.cap (1) << endl; + unsigned chs = chapterRegExp.cap (1).toInt (); + if ( chs > 100) chs = 100; + for (unsigned c = 1; c <= chs; c++) + m_dvdchaptermenu->insertItem (QString::number (c), c); + } else + return false; + return true; +} + +KDE_NO_EXPORT void KMPlayerDVDSource::activate () { + m_start_play = m_auto_play; + m_current_title = -1; + setURL (KURL ("dvd://")); + buildArguments (); + m_menu->insertItem (i18n ("&Titles"), m_dvdtitlemenu); + m_menu->insertItem (i18n ("&Chapters"), m_dvdchaptermenu); + if (!m_player->settings ()->mplayerpost090) { + m_menu->insertItem (i18n ("Audio &Language"), m_dvdlanguagemenu); + m_menu->insertItem (i18n ("&SubTitles"), m_dvdsubtitlemenu); + connect (m_dvdsubtitlemenu, SIGNAL (activated (int)), + this, SLOT (subtitleMenuClicked (int))); + connect (m_dvdlanguagemenu, SIGNAL (activated (int)), + this, SLOT (languageMenuClicked (int))); + } + connect (m_dvdtitlemenu, SIGNAL (activated (int)), + this, SLOT (titleMenuClicked (int))); + connect (m_dvdchaptermenu, SIGNAL (activated (int)), + this, SLOT (chapterMenuClicked (int))); + if (m_start_play) + QTimer::singleShot (0, m_player, SLOT (play ())); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::setIdentified (bool b) { + KMPlayer::Source::setIdentified (b); + m_start_play = true; + if (m_current_title < 0 || m_current_title >= int (m_dvdtitlemenu->count())) + m_current_title = 0; + if (m_dvdtitlemenu->count ()) + m_dvdtitlemenu->setItemChecked (m_current_title, true); + else + m_current_title = -1; // hmmm + if (m_dvdchaptermenu->count ()) m_dvdchaptermenu->setItemChecked (0, true); + // TODO remember lang/subtitles settings + if (m_dvdlanguagemenu->count()) + m_dvdlanguagemenu->setItemChecked (m_dvdlanguagemenu->idAt (0), true); + buildArguments (); + m_app->slotStatusMsg (i18n ("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::deactivate () { + if (m_player->view ()) { + m_dvdtitlemenu->clear (); + m_dvdsubtitlemenu->clear (); + m_dvdchaptermenu->clear (); + m_dvdlanguagemenu->clear (); + m_menu->removeItemAt (m_menu->count () - 1); + m_menu->removeItemAt (m_menu->count () - 1); + if (!m_player->settings ()->mplayerpost090) { + m_menu->removeItemAt (m_menu->count () - 1); + m_menu->removeItemAt (m_menu->count () - 1); + disconnect (m_dvdsubtitlemenu, SIGNAL (activated (int)), + this, SLOT (subtitleMenuClicked (int))); + disconnect (m_dvdlanguagemenu, SIGNAL (activated (int)), + this, SLOT (languageMenuClicked (int))); + } + disconnect (m_dvdtitlemenu, SIGNAL (activated (int)), + this, SLOT (titleMenuClicked (int))); + disconnect (m_dvdchaptermenu, SIGNAL (activated (int)), + this, SLOT (chapterMenuClicked (int))); + } +} + +KDE_NO_EXPORT void KMPlayerDVDSource::buildArguments () { + QString url ("dvd://"); + if (m_document) { + if (m_current_title > 0) + url += QString::number (m_current_title); + m_document->mrl ()->src = url; + } else + setURL (KURL (url)); + m_options = QString (m_identified ? "" : "-v "); + if (m_identified) { + for (unsigned i = 0; i < m_dvdsubtitlemenu->count (); i++) + if (m_dvdsubtitlemenu->isItemChecked (m_dvdsubtitlemenu->idAt (i))) + m_options += "-sid " + QString::number (m_dvdsubtitlemenu->idAt(i)); + for (unsigned i = 0; i < m_dvdchaptermenu->count (); i++) + if (m_dvdchaptermenu->isItemChecked (i)) + m_options += QString (" -chapter %1").arg (i); + for (unsigned i = 0; i < m_dvdlanguagemenu->count (); i++) + if (m_dvdlanguagemenu->isItemChecked (m_dvdlanguagemenu->idAt (i))) + m_options += " -aid " + QString::number(m_dvdlanguagemenu->idAt(i)); + if (m_player->settings ()->dvddevice.length () > 0) + m_options += QString(" -dvd-device ") + m_player->settings()->dvddevice; + } + m_recordcmd = m_options + QString (" -vf scale -zoom"); +} + +KDE_NO_EXPORT QString KMPlayerDVDSource::filterOptions () { + KMPlayer::Settings * settings = m_player->settings (); + if (!settings->disableppauto) + return KMPlayer::Source::filterOptions (); + return QString (""); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::titleMenuClicked (int id) { + if (m_current_title != id) { + m_player->stop (); + m_current_title = id; + m_identified = false; + buildArguments (); + m_dvdtitlemenu->clear (); + m_dvdsubtitlemenu->clear (); + m_dvdchaptermenu->clear (); + m_dvdlanguagemenu->clear (); + if (m_start_play) + QTimer::singleShot (0, m_player, SLOT (play ())); + } +} + +KDE_NO_EXPORT void KMPlayerDVDSource::play () { + buildArguments (); + if (m_start_play) { + m_player->stop (); + QTimer::singleShot (0, m_player, SLOT (play ())); + } +} + +KDE_NO_EXPORT void KMPlayerDVDSource::subtitleMenuClicked (int id) { + menuItemClicked (m_dvdsubtitlemenu, id); + play (); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::languageMenuClicked (int id) { + menuItemClicked (m_dvdlanguagemenu, id); + play (); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::chapterMenuClicked (int id) { + menuItemClicked (m_dvdchaptermenu, id); + play (); +} + +KDE_NO_EXPORT QString KMPlayerDVDSource::prettyName () { + return i18n ("DVD"); +} + +static const char * strPlayDVD = "Immediately Play DVD"; + +KDE_NO_EXPORT void KMPlayerDVDSource::write (KConfig * config) { + config->setGroup (strMPlayerGroup); + config->writeEntry (strPlayDVD, m_auto_play); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::read (KConfig * config) { + config->setGroup (strMPlayerGroup); + m_auto_play = config->readBoolEntry (strPlayDVD, true); +} + +KDE_NO_EXPORT void KMPlayerDVDSource::sync (bool fromUI) { + if (fromUI) { + m_auto_play = m_configpage->autoPlayDVD->isChecked (); + m_player->settings ()->dvddevice = m_configpage->dvddevice->lineEdit()->text (); + } else { + m_configpage->autoPlayDVD->setChecked (m_auto_play); + m_configpage->dvddevice->lineEdit()->setText (m_player->settings ()->dvddevice); + } +} + +KDE_NO_EXPORT void KMPlayerDVDSource::prefLocation (QString & item, QString & icon, QString & tab) { + item = i18n ("Source"); + icon = QString ("source"); + tab = i18n ("DVD"); +} + +KDE_NO_EXPORT QFrame * KMPlayerDVDSource::prefPage (QWidget * parent) { + m_configpage = new KMPlayerPrefSourcePageDVD (parent); + return m_configpage; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerDVDNavSource::KMPlayerDVDNavSource (KMPlayerApp * app, QPopupMenu * m) + : KMPlayerMenuSource (i18n ("DVDNav"), app, m, "dvdnavsource") { + m_menu->insertTearOffHandle (-1, 0); + setURL (KURL ("dvd://")); +} + +KDE_NO_CDTOR_EXPORT KMPlayerDVDNavSource::~KMPlayerDVDNavSource () {} + +KDE_NO_EXPORT void KMPlayerDVDNavSource::activate () { + setURL (KURL ("dvd://")); + play (); +} + +KDE_NO_EXPORT void KMPlayerDVDNavSource::deactivate () { +} + +KDE_NO_EXPORT void KMPlayerDVDNavSource::play () { + if (!m_menu->findItem (DVDNav_previous)) { + m_menu->insertItem (i18n ("&Previous"), this, SLOT (navMenuClicked (int)), 0, DVDNav_previous); + m_menu->insertItem (i18n ("&Next"), this, SLOT (navMenuClicked (int)), 0, DVDNav_next); + m_menu->insertItem (i18n ("&Root"), this, SLOT (navMenuClicked (int)), 0, DVDNav_root); + m_menu->insertItem (i18n ("&Up"), this, SLOT (navMenuClicked (int)), 0, DVDNav_up); + } + QTimer::singleShot (0, m_player, SLOT (play ())); + connect (this, SIGNAL (stopPlaying ()), this, SLOT(finished ())); +} + +KDE_NO_EXPORT void KMPlayerDVDNavSource::finished () { + disconnect (this, SIGNAL (stopPlaying ()), this, SLOT(finished ())); + m_menu->removeItem (DVDNav_previous); + m_menu->removeItem (DVDNav_next); + m_menu->removeItem (DVDNav_root); + m_menu->removeItem (DVDNav_up); +} + +KDE_NO_EXPORT void KMPlayerDVDNavSource::navMenuClicked (int id) { + switch (id) { + case DVDNav_start: + break; + case DVDNav_previous: + m_app->view ()->viewer ()->sendKeyEvent ('p'); + break; + case DVDNav_next: + m_app->view ()->viewer ()->sendKeyEvent ('n'); + break; + case DVDNav_root: + m_app->view ()->viewer ()->sendKeyEvent ('r'); + break; + case DVDNav_up: + m_app->view ()->viewer ()->sendKeyEvent ('u'); + break; + } +} + +KDE_NO_EXPORT QString KMPlayerDVDNavSource::prettyName () { + return i18n ("DVD"); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageVCD::KMPlayerPrefSourcePageVCD (QWidget * parent) + : QFrame (parent) { + QVBoxLayout *layout = new QVBoxLayout (this, 5, 2); + autoPlayVCD = new QCheckBox (i18n ("Auto play after opening a VCD"), this, 0); + QWhatsThis::add(autoPlayVCD, i18n ("Start playing VCD right after opening VCD")); + QLabel *vcdDevicePathLabel = new QLabel (i18n ("VCD (CDROM) device:"), this, 0); + vcddevice= new KURLRequester ("/dev/cdrom", this, 0); + QWhatsThis::add(vcddevice, i18n ("Path to your CDROM/DVD device, you must have read rights to this device")); + layout->addWidget (autoPlayVCD); + layout->addItem (new QSpacerItem (0, 10, QSizePolicy::Minimum, QSizePolicy::Minimum)); + layout->addWidget (vcdDevicePathLabel); + layout->addWidget (vcddevice); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerVCDSource::KMPlayerVCDSource (KMPlayerApp * a, QPopupMenu * m) + : KMPlayerMenuSource (i18n ("VCD"), a, m, "vcdsource"), m_configpage (0L) { + m_player->settings ()->addPage (this); + setURL (KURL ("vcd://")); +} + +KDE_NO_CDTOR_EXPORT KMPlayerVCDSource::~KMPlayerVCDSource () { +} + +KDE_NO_EXPORT bool KMPlayerVCDSource::processOutput (const QString & str) { + if (KMPlayer::Source::processOutput (str)) + return true; + if (m_identified) + return false; + //kdDebug () << "scanning " << cstr << endl; + QRegExp * patterns = static_cast<KMPlayer::MPlayer *> (m_player->players () ["mplayer"])->configPage ()->m_patterns; + QRegExp & trackRegExp = patterns [KMPlayer::MPlayerPreferencesPage::pat_vcdtrack]; + if (trackRegExp.search (str) > -1) { + m_document->state = KMPlayer::Element::state_deferred; + m_document->appendChild (new KMPlayer::GenericMrl (m_document, QString ("vcd://") + trackRegExp.cap (1), i18n ("Track ") + trackRegExp.cap (1))); + kdDebug () << "track " << trackRegExp.cap (1) << endl; + return true; + } + return false; +} + +KDE_NO_EXPORT void KMPlayerVCDSource::activate () { + m_player->stop (); + init (); + m_start_play = m_auto_play; + setURL (KURL ("vcd://")); + buildArguments (); + if (m_start_play) + QTimer::singleShot (0, m_player, SLOT (play ())); +} + +KDE_NO_EXPORT void KMPlayerVCDSource::deactivate () { +} + +KDE_NO_EXPORT void KMPlayerVCDSource::setIdentified (bool b) { + KMPlayer::Source::setIdentified (b); + if (!m_current || !m_document->hasChildNodes ()) + m_current = m_document; + m_player->updateTree (); + buildArguments (); + if (m_current->state == KMPlayer::Element::state_deferred) + m_current->undefer (); + m_app->slotStatusMsg (i18n ("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerVCDSource::buildArguments () { + QString url ("vcd://"); + if (m_current && m_current != m_document) + url += m_current->mrl ()->src; + m_options.truncate (0); + if (m_player->settings ()->vcddevice.length () > 0) + m_options+=QString(" -cdrom-device ") + m_player->settings()->vcddevice; + m_recordcmd = m_options; +} + +KDE_NO_EXPORT QString KMPlayerVCDSource::prettyName () { + return i18n ("VCD"); +} + +static const char * strPlayVCD = "Immediately Play VCD"; + +KDE_NO_EXPORT void KMPlayerVCDSource::write (KConfig * config) { + config->setGroup (strMPlayerGroup); + config->writeEntry (strPlayVCD, m_auto_play); +} + +KDE_NO_EXPORT void KMPlayerVCDSource::read (KConfig * config) { + config->setGroup (strMPlayerGroup); + m_auto_play = config->readBoolEntry (strPlayVCD, true); +} + +KDE_NO_EXPORT void KMPlayerVCDSource::sync (bool fromUI) { + if (fromUI) { + m_auto_play = m_configpage->autoPlayVCD->isChecked (); + m_player->settings ()->vcddevice = m_configpage->vcddevice->lineEdit()->text (); + } else { + m_configpage->autoPlayVCD->setChecked (m_auto_play); + m_configpage->vcddevice->lineEdit()->setText (m_player->settings ()->vcddevice); + } +} + +KDE_NO_EXPORT void KMPlayerVCDSource::prefLocation (QString & item, QString & icon, QString & tab) { + item = i18n ("Source"); + icon = QString ("source"); + tab = i18n ("VCD"); +} + +KDE_NO_EXPORT QFrame * KMPlayerVCDSource::prefPage (QWidget * parent) { + m_configpage = new KMPlayerPrefSourcePageVCD (parent); + return m_configpage; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerAudioCDSource::KMPlayerAudioCDSource (KMPlayerApp * a, QPopupMenu * m) + : KMPlayerMenuSource (i18n ("Audio CD"), a, m, "audiocdsource") { + setURL (KURL ("cdda://")); +} + +KDE_NO_CDTOR_EXPORT KMPlayerAudioCDSource::~KMPlayerAudioCDSource () { +} + +KDE_NO_EXPORT bool KMPlayerAudioCDSource::processOutput (const QString & str) { + if (KMPlayer::Source::processOutput (str)) + return true; + if (m_identified) + return false; + //kdDebug () << "scanning " << str << endl; + QRegExp * patterns = static_cast<KMPlayer::MPlayer *> (m_player->players () ["mplayer"])->configPage ()->m_patterns; + QRegExp & trackRegExp = patterns [KMPlayer::MPlayerPreferencesPage::pat_cdromtracks]; + if (trackRegExp.search (str) > -1) { + //if (m_document->state != KMPlayer::Element::state_deferred) + // m_document->defer (); + int nt = trackRegExp.cap (1).toInt (); + kdDebug () << "tracks " << trackRegExp.cap (1) << endl; + for (int i = 0; i < nt; i++) + m_document->appendChild (new KMPlayer::GenericMrl (m_document, QString ("cdda://%1").arg (i+1), i18n ("Track %1").arg (i+1))); + return true; + } + return false; +} + +KDE_NO_EXPORT void KMPlayerAudioCDSource::activate () { + m_player->stop (); + init (); + //m_start_play = m_auto_play; + setURL (KURL ("cdda://")); + buildArguments (); + //if (m_start_play) + QTimer::singleShot (0, m_player, SLOT (play ())); +} + +KDE_NO_EXPORT void KMPlayerAudioCDSource::deactivate () { +} + +KDE_NO_EXPORT void KMPlayerAudioCDSource::setIdentified (bool b) { + KMPlayer::Source::setIdentified (b); + if (!m_current || !m_document->hasChildNodes ()) + m_current = m_document; + buildArguments (); + if (m_current == m_document && m_document->hasChildNodes ()) { + m_back_request = m_document->firstChild (); + m_player->process ()->stop (); + } + m_player->updateTree (); + //if (m_current->state == KMPlayer::Element::state_deferred) + // m_current->undefer (); + m_app->slotStatusMsg (i18n ("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerAudioCDSource::buildArguments () { + QString url ("cdda://"); + if (m_current && m_current != m_document) + url += m_current->mrl ()->src; + m_options = "-cdda speed=3"; + if (m_player->settings ()->vcddevice.length () > 0) + m_options+=QString(" -cdrom-device ") + m_player->settings()->vcddevice; + m_recordcmd = m_options; +} + +KDE_NO_EXPORT QString KMPlayerAudioCDSource::prettyName () { + return i18n ("Audio CD"); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerPipeSource::KMPlayerPipeSource (KMPlayerApp * a) + : KMPlayer::Source (i18n ("Pipe"), a->player (), "pipesource"), m_app (a) { +} + +KDE_NO_CDTOR_EXPORT KMPlayerPipeSource::~KMPlayerPipeSource () { +} + +KDE_NO_EXPORT bool KMPlayerPipeSource::hasLength () { + return false; +} + +KDE_NO_EXPORT bool KMPlayerPipeSource::isSeekable () { + return false; +} + +KDE_NO_EXPORT void KMPlayerPipeSource::activate () { + // dangerous !! if (!m_url.protocol ().compare ("kmplayer")) + // m_pipecmd = KURL::decode_string (m_url.path ()).mid (1); + setURL (KURL ("stdin://")); + KMPlayer::GenericMrl * gen = new KMPlayer::GenericMrl (m_document, QString ("stdin://"), m_pipecmd); + gen->bookmarkable = false; + m_document->appendChild (gen); + m_recordcmd = m_options = QString ("-"); // or m_url? + m_identified = true; + reset (); + QTimer::singleShot (0, m_player, SLOT (play ())); + m_app->slotStatusMsg (i18n ("Ready.")); +} + +KDE_NO_EXPORT void KMPlayerPipeSource::deactivate () { +} + +KDE_NO_EXPORT QString KMPlayerPipeSource::prettyName () { + return i18n ("Pipe - %1").arg (m_pipecmd); +} + +KDE_NO_EXPORT void KMPlayerPipeSource::setCommand (const QString & cmd) { + m_pipecmd = cmd; + if (m_document) + m_document->mrl ()->pretty_name = cmd; +} + +#include "kmplayer.moc" +#include "kmplayerappsource.moc" diff --git a/src/kmplayerappsource.h b/src/kmplayerappsource.h new file mode 100644 index 0000000..86378f3 --- /dev/null +++ b/src/kmplayerappsource.h @@ -0,0 +1,205 @@ +/*************************************************************************** + kmplayersource.h - description + ------------------- + begin : Sat Mar 24 16:14:51 CET 2003 + copyright : (C) 2003 by Koos Vriezen + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KMPLAYERAPPSOURCE_H +#define KMPLAYERAPPSOURCE_H + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qframe.h> + +#include <kurl.h> + +#include "kmplayersource.h" +#include "kmplayerconfig.h" + + +class KMPlayerApp; +class KURLRequester; +class QPopupMenu; +class QMenuItem; +class QCheckBox; +class QLineEdit; +class TVInput; +class TVChannel; + +/* + * Base class for sources having a sub menu in the application + */ +class KMPLAYER_NO_EXPORT KMPlayerMenuSource : public KMPlayer::Source { + Q_OBJECT +public: + KMPlayerMenuSource (const QString & n, KMPlayerApp * app, QPopupMenu * m, const char * src); + virtual ~KMPlayerMenuSource (); +protected: + void menuItemClicked (QPopupMenu * menu, int id); + QPopupMenu * m_menu; + KMPlayerApp * m_app; +}; + +/* + * Preference page for DVD + */ +class KMPLAYER_NO_EXPORT KMPlayerPrefSourcePageDVD : public QFrame { + Q_OBJECT +public: + KMPlayerPrefSourcePageDVD (QWidget * parent); + ~KMPlayerPrefSourcePageDVD () {} + + QCheckBox * autoPlayDVD; + KURLRequester * dvddevice; +}; + +/* + * Source from DVD + */ +class KMPLAYER_NO_EXPORT KMPlayerDVDSource : public KMPlayerMenuSource, public KMPlayer::PreferencesPage { + Q_OBJECT +public: + KMPlayerDVDSource (KMPlayerApp * app, QPopupMenu * m); + virtual ~KMPlayerDVDSource (); + virtual bool processOutput (const QString & line); + virtual QString filterOptions (); + virtual void setIdentified (bool b = true); + virtual QString prettyName (); + virtual void write (KConfig *); + virtual void read (KConfig *); + virtual void sync (bool); + virtual void prefLocation (QString & item, QString & icon, QString & tab); + virtual QFrame * prefPage (QWidget * parent); +public slots: + virtual void activate (); + virtual void deactivate (); + + void titleMenuClicked (int id); + void subtitleMenuClicked (int id); + void languageMenuClicked (int id); + void chapterMenuClicked (int id); +private: + void buildArguments (); + void play (); + QPopupMenu * m_dvdtitlemenu; + QPopupMenu * m_dvdchaptermenu; + QPopupMenu * m_dvdlanguagemenu; + QPopupMenu * m_dvdsubtitlemenu; + KMPlayer::NodePtr disks; + KMPlayerPrefSourcePageDVD * m_configpage; + int m_current_title; + bool m_start_play; +}; + + +/* + * Source from DVDNav + */ +class KMPLAYER_NO_EXPORT KMPlayerDVDNavSource : public KMPlayerMenuSource { + Q_OBJECT +public: + KMPlayerDVDNavSource (KMPlayerApp * app, QPopupMenu * m); + virtual ~KMPlayerDVDNavSource (); + virtual QString prettyName (); +public slots: + virtual void activate (); + virtual void deactivate (); + virtual void play (); + + void finished (); + void navMenuClicked (int id); +}; + + +/* + * Preference page for VCD + */ +class KMPLAYER_NO_EXPORT KMPlayerPrefSourcePageVCD : public QFrame { + Q_OBJECT +public: + KMPlayerPrefSourcePageVCD (QWidget * parent); + ~KMPlayerPrefSourcePageVCD () {} + KURLRequester * vcddevice; + QCheckBox *autoPlayVCD; +}; + + +/* + * Source from VCD + */ +class KMPLAYER_NO_EXPORT KMPlayerVCDSource : public KMPlayerMenuSource, public KMPlayer::PreferencesPage { + Q_OBJECT +public: + KMPlayerVCDSource (KMPlayerApp * app, QPopupMenu * m); + virtual ~KMPlayerVCDSource (); + virtual bool processOutput (const QString & line); + virtual void setIdentified (bool b = true); + virtual QString prettyName (); + virtual void write (KConfig *); + virtual void read (KConfig *); + virtual void sync (bool); + virtual void prefLocation (QString & item, QString & icon, QString & tab); + virtual QFrame * prefPage (QWidget * parent); +public slots: + virtual void activate (); + virtual void deactivate (); +private: + void buildArguments (); + KMPlayerPrefSourcePageVCD * m_configpage; + bool m_start_play; +}; + + +/* + * Source from AudoCD + */ +class KMPLAYER_NO_EXPORT KMPlayerAudioCDSource : public KMPlayerMenuSource { + Q_OBJECT +public: + KMPlayerAudioCDSource (KMPlayerApp * app, QPopupMenu * m); + virtual ~KMPlayerAudioCDSource (); + virtual bool processOutput (const QString & line); + virtual void setIdentified (bool b = true); + virtual QString prettyName (); +public slots: + virtual void activate (); + virtual void deactivate (); +private: + void buildArguments (); +}; + + +/* + * Source from stdin (for the backends, not kmplayer) + */ +class KMPLAYER_NO_EXPORT KMPlayerPipeSource : public KMPlayer::Source { + Q_OBJECT +public: + KMPlayerPipeSource (KMPlayerApp * app); + virtual ~KMPlayerPipeSource (); + virtual bool hasLength (); + virtual bool isSeekable (); + void setCommand (const QString & cmd); + virtual QString prettyName (); +public slots: + virtual void activate (); + virtual void deactivate (); +private: + KMPlayerApp * m_app; +}; + +#endif // KMPLAYERAPPSOURCE_H diff --git a/src/kmplayerbroadcast.cpp b/src/kmplayerbroadcast.cpp new file mode 100644 index 0000000..34045e2 --- /dev/null +++ b/src/kmplayerbroadcast.cpp @@ -0,0 +1,670 @@ +/* this file is part of the kmplayer application + copyright (c) 2003 koos vriezen <[email protected]> + + 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 02110-1301, usa. +*/ +#include <algorithm> + +#include <qlayout.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qtable.h> +#include <qstringlist.h> +#include <qcombobox.h> +#include <qlistbox.h> +#include <qlineedit.h> +#include <qwhatsthis.h> +#include <qtabwidget.h> +#include <qcursor.h> +#include <qdir.h> +#include <qfile.h> +#include <qtimer.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kled.h> +#include <kconfig.h> +#include <kprocess.h> +#include <kprocctrl.h> +#include <kmessagebox.h> + +#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.length ()); +} + +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<FFServerSetting>()); + 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 <kglobal.h> +#include <kstandarddirs.h> + +static const char ffserverconf[] = +"Port %d\nBindAddress %s\nMaxClients %d\nMaxBandwidth %d\n" +"CustomLog -\nNoDaemon\n" +"<Feed kmplayer.ffm>\nFile %s\nFileMaxSize %dK\nACL allow 127.0.0.1\n</Feed>\n" +"<Stream video.%s>\nFeed kmplayer.ffm\n%s\n%s%s\n</Stream>\n" +"<Stream stat.html>\nFormat status\nACL allow localhost\n</Stream>\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 = 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.length ()); + 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, 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 (m_player->source (), KMPlayer::NodePtr())) { + KMessageBox::error (m_configpage, i18n ("Failed to start ffmpeg."), i18n ("Error")); + stopProcess (m_ffserver_process); + goto bail_out; + } + if (m_ffmpeg_process->playing ()) { + 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/kmplayerbroadcast.h b/src/kmplayerbroadcast.h new file mode 100644 index 0000000..2b763db --- /dev/null +++ b/src/kmplayerbroadcast.h @@ -0,0 +1,194 @@ +/* this file is part of the kmplayer application + copyright (c) 2003 koos vriezen <[email protected]> + + 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 02110-1301, usa. +*/ + +#ifndef _KMPLAYER_BROADCAST_SOURCE_H_ +#define _KMPLAYER_BROADCAST_SOURCE_H_ + +#include <list> +#include <vector> + +#include <qframe.h> +#include <qguardedptr.h> + +#include "kmplayerappsource.h" +#include "kmplayerprocess.h" +#include "kmplayerconfig.h" + +class KMPlayerPrefBroadcastPage; // broadcast +class KMPlayerPrefBroadcastFormatPage; // broadcast format +class QListBox; +class QComboBox; +class QLineEdit; +class QTable; +class QPushButton; +class KLed; + +namespace KMPlayer { + class FFMpeg; +} + +class KMPLAYER_NO_EXPORT FFServerSetting { +public: + 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); + KDE_NO_CDTOR_EXPORT FFServerSetting (const QStringList & sl) { *this = sl; } + KDE_NO_CDTOR_EXPORT ~FFServerSetting () {} + int index; + QString name; + QString format; + QString audiocodec; + QString audiobitrate; + QString audiosamplerate; + QString videocodec; + QString videobitrate; + QString quality; + QString framerate; + QString gopsize; + QString width; + QString height; + QStringList acl; + FFServerSetting & operator = (const QStringList &); + FFServerSetting & operator = (const FFServerSetting & fs); + const QStringList list (); + QString & ffconfig (QString & buf); +}; + +typedef std::vector <FFServerSetting *> FFServerSettingList; + + +class KMPLAYER_NO_EXPORT KMPlayerPrefBroadcastPage : public QFrame { + Q_OBJECT +public: + KMPlayerPrefBroadcastPage (QWidget * parent); + KDE_NO_CDTOR_EXPORT ~KMPlayerPrefBroadcastPage () {} + + QLineEdit * bindaddress; + QLineEdit * port; + QLineEdit * maxclients; + QLineEdit * maxbandwidth; + QLineEdit * feedfile; + QLineEdit * feedfilesize; +}; + +class KMPLAYER_NO_EXPORT KMPlayerPrefBroadcastFormatPage : public QFrame { + Q_OBJECT +public: + KMPlayerPrefBroadcastFormatPage (QWidget * parent, FFServerSettingList &); + KDE_NO_CDTOR_EXPORT ~KMPlayerPrefBroadcastFormatPage () {} + + QListBox * profilelist; + QComboBox * format; + QLineEdit * audiocodec; + QLineEdit * audiobitrate; + QLineEdit * audiosamplerate; + QLineEdit * videocodec; + QLineEdit * videobitrate; + QLineEdit * quality; + QLineEdit * framerate; + QLineEdit * gopsize; + QLineEdit * moviewidth; + QLineEdit * movieheight; + QLineEdit * profile; + QPushButton * startbutton; + KLed * serverled; + KLed * feedled; + void setSettings (const FFServerSetting &); + void getSettings (FFServerSetting &); +private slots: + void slotIndexChanged (int index); + void slotItemHighlighted (int index); + void slotTextChanged (const QString &); + void slotLoad (); + void slotSave (); + void slotDelete (); +private: + QTable * accesslist; + QPushButton * load; + QPushButton * save; + QPushButton * del; + FFServerSettingList & profiles; +}; + + +/* + * Preference page for ffmpeg commandline arguments + */ +class KMPLAYER_NO_EXPORT KMPlayerFFServerConfig : public KMPlayer::PreferencesPage { +public: + KMPlayerFFServerConfig (); + KDE_NO_CDTOR_EXPORT ~KMPlayerFFServerConfig () {} + virtual void write (KConfig *); + virtual void read (KConfig *); + virtual void sync (bool fromUI); + virtual void prefLocation (QString & item, QString & icon, QString & tab); + virtual QFrame * prefPage (QWidget * parent); + int ffserverport; + int maxclients; + int maxbandwidth; + QString feedfile; + int feedfilesize; + QString bindaddress; +private: + QGuardedPtr <KMPlayerPrefBroadcastPage> m_configpage; +}; + +/* + * Preference page for ffserver + */ +class KMPLAYER_NO_EXPORT KMPlayerBroadcastConfig : public QObject, public KMPlayer::PreferencesPage { + Q_OBJECT +public: + KMPlayerBroadcastConfig (KMPlayer::PartBase * player, KMPlayerFFServerConfig * fsc); + KDE_NO_CDTOR_EXPORT ~KMPlayerBroadcastConfig (); + + virtual void write (KConfig *); + virtual void read (KConfig *); + virtual void sync (bool fromUI); + virtual void prefLocation (QString & item, QString & icon, QString & tab); + virtual QFrame * prefPage (QWidget * parent); + + bool broadcasting () const; + void stopServer (); + KDE_NO_EXPORT const QString & serverURL () const { return m_ffserver_url; } + + FFServerSetting ffserversettings; + FFServerSettingList ffserversettingprofiles; +signals: + void broadcastStarted (); + void broadcastStopped (); +private slots: + void processOutput (KProcess *, char *, int); + void processStopped (KProcess * process); + void startServer (); + void startFeed (); + void stateChange (KMPlayer::Process::State, KMPlayer::Process::State); + void sourceChanged (KMPlayer::Source *, KMPlayer::Source *); +private: + KMPlayer::PartBase * m_player; + KMPlayerFFServerConfig * m_ffserverconfig; + QGuardedPtr <KMPlayerPrefBroadcastFormatPage> m_configpage; + KMPlayer::FFMpeg * m_ffmpeg_process; + KProcess * m_ffserver_process; + bool m_endserver; + QString m_ffserver_out; + QString m_ffserver_url; +}; + + +#endif //_KMPLAYER_BROADCAST_SOURCE_H_ diff --git a/src/kmplayerconfig.cpp b/src/kmplayerconfig.cpp new file mode 100644 index 0000000..bbc13b1 --- /dev/null +++ b/src/kmplayerconfig.cpp @@ -0,0 +1,749 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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 <algorithm> +#include <functional> +#include <config.h> +#include <qcheckbox.h> +#include <qtextedit.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qtabwidget.h> +#include <qslider.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qbuttongroup.h> +#include <qfileinfo.h> + +#include <kurlrequester.h> +#include <klineedit.h> +#include <kstatusbar.h> + +#include <kconfig.h> +#include <kapplication.h> +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcombobox.h> +#include <kmessagebox.h> +#include <kglobalsettings.h> + +#include "kmplayersource.h" +#include "kmplayerconfig.h" +#include "kmplayerpartbase.h" +#include "kmplayerprocess.h" +#include "playlistview.h" +#include "viewarea.h" +#include "pref.h" + +using namespace KMPlayer; + +static OutputDriver _ads[] = { + { "alsa,oss,sdl,arts", i18n ("Auto") }, + { "oss", i18n ("Open Sound System") }, + { "sdl", i18n ("Simple DirectMedia Layer") }, + { "alsa", i18n ("Advanced Linux Sound Architecture") }, + { "arts", i18n ("Analog Real-Time Synthesizer") }, + { "jack", i18n ("JACK Audio Connection Kit") }, + { "openal", i18n ("OpenAL") }, + { "esd", i18n ("Enlightened Sound Daemon") }, + { "alsa5", i18n ("Advanced Linux Sound Architecture v0.5") }, + { "alsa9", i18n ("Advanced Linux Sound Architecture v0.9") }, + { "", i18n ("Use back-end defaults") }, + { 0, QString () } +}; + +static OutputDriver _vds [] = { + { "xv,sdl,x11", i18n ("Auto") }, + { "x11", i18n ("X11Shm") }, + { "xvidix", i18n ("XVidix") }, + { "xvmc,xv", i18n ("XvMC") }, + { "sdl", i18n ("SDL") }, + { "gl", i18n ("OpenGL") }, + { "gl2", i18n ("OpenGL MT") }, + { "xv", i18n ("XVideo") }, + { 0, QString () } +}; + +static const int ADRIVER_ARTS_INDEX = 4; + + +KDE_NO_CDTOR_EXPORT Settings::Settings (PartBase * player, KConfig * config) + : pagelist (0L), configdialog (0L), m_config (config), m_player (player) { + audiodrivers = _ads; + videodrivers = _vds; + colors [ColorSetting::playlist_background].title = i18n ("Playlist background"); + colors [ColorSetting::playlist_background].option = "PlaylistBackground"; + colors [ColorSetting::playlist_background].color = KGlobalSettings::baseColor (); + colors [ColorSetting::playlist_foreground].title = i18n ("Playlist foreground"); + colors [ColorSetting::playlist_foreground].option = "PlaylistForeground"; + colors [ColorSetting::playlist_foreground].color = KGlobalSettings::textColor(); + colors [ColorSetting::console_background].title =i18n("Console background"); + colors [ColorSetting::playlist_active].title = i18n("Playlist active item"); + colors [ColorSetting::playlist_active].option = "PlaylistActive"; + colors [ColorSetting::playlist_active].color = KGlobalSettings::linkColor(); + colors [ColorSetting::console_background].option = "ConsoleBackground"; + colors [ColorSetting::console_background].color = QColor (0, 0, 0); + colors [ColorSetting::console_foreground].title = i18n ("Console foreground"); + colors [ColorSetting::console_foreground].option = "ConsoleForeground"; + colors [ColorSetting::console_foreground].color = QColor (0xB2, 0xB2, 0xB2); + colors [ColorSetting::video_background].title = i18n ("Video background"); + colors [ColorSetting::video_background].option = "VideoBackground"; + colors [ColorSetting::video_background].color = QColor (0, 0, 0); + colors [ColorSetting::area_background].title = i18n ("Viewing area background"); + colors [ColorSetting::area_background].option = "ViewingAreaBackground"; + colors [ColorSetting::area_background].color = QColor (0, 0, 0); + colors [ColorSetting::infowindow_background].title = i18n ("Info window background"); + colors [ColorSetting::infowindow_background].option ="InfoWindowBackground"; + colors [ColorSetting::infowindow_background].color = KGlobalSettings::baseColor (); + colors [ColorSetting::infowindow_foreground].title = i18n ("Info window foreground"); + colors [ColorSetting::infowindow_foreground].option ="InfoWindowForeground"; + colors [ColorSetting::infowindow_foreground].color = KGlobalSettings::textColor(); + fonts [FontSetting::playlist].title = i18n ("Playlist"); + fonts [FontSetting::playlist].option = "PlaylistFont"; + fonts [FontSetting::playlist].font = KGlobalSettings::generalFont(); + fonts [FontSetting::playlist].font.setItalic (true); + fonts [FontSetting::infowindow].title = i18n ("Info window"); + fonts [FontSetting::infowindow].option = "InfoWindowFont"; + fonts [FontSetting::infowindow].font = KGlobalSettings::generalFont(); +} + +KDE_NO_CDTOR_EXPORT Settings::~Settings () { + // configdialog should be destroyed when the view is destroyed + //delete configdialog; +} + +KDE_EXPORT const char * strMPlayerGroup = "MPlayer"; +const char * strGeneralGroup = "General Options"; +static const char * strKeepSizeRatio = "Keep Size Ratio"; +static const char * strRememberSize = "Remember Size"; +static const char * strAutoResize = "Auto Resize"; +static const char * strDockSysTray = "Dock in System Tray"; +static const char * strNoIntro = "No Intro"; +static const char * strVolume = "Volume"; +static const char * strContrast = "Contrast"; +static const char * strBrightness = "Brightness"; +static const char * strHue = "Hue"; +static const char * strSaturation = "Saturation"; +static const char * strURLList = "URL List"; +static const char * strSubURLList = "URL Sub Title List"; +static const char * strPrefBitRate = "Prefered Bitrate"; +static const char * strMaxBitRate = "Maximum Bitrate"; +//static const char * strUseArts = "Use aRts"; +static const char * strVoDriver = "Video Driver"; +static const char * strAoDriver = "Audio Driver"; +static const char * strLoop = "Loop"; +static const char * strFrameDrop = "Frame Drop"; +static const char * strAdjustVolume = "Auto Adjust Volume"; +static const char * strAdjustColors = "Auto Adjust Colors"; +static const char * strAddConfigButton = "Add Configure Button"; +static const char * strAddPlaylistButton = "Add Playlist Button"; +static const char * strAddRecordButton = "Add Record Button"; +static const char * strAddBroadcastButton = "Add Broadcast Button"; +static const char * strPostMPlayer090 = "Post MPlayer 0.90"; +//static const char * strAutoHideSlider = "Auto Hide Slider"; +static const char * strSeekTime = "Forward/Backward Seek Time"; +static const char * strDVDDevice = "DVD Device"; +//static const char * strShowDVD = "Show DVD Menu"; +//static const char * strShowVCD = "Show VCD Menu"; +static const char * strVCDDevice = "VCD Device"; +const char * strUrlBackend = "URL Backend"; +static const char * strAllowHref = "Allow HREF"; +// postproc thingies +static const char * strPPGroup = "Post processing options"; +static const char * strPostProcessing = "Post processing"; +static const char * strDisablePPauto = "Automaticly disable post processing"; +static const char * strPP_Default = "Default preset"; +static const char * strPP_Fast = "Fast preset"; +static const char * strPP_Custom = "Custom preset"; + +static const char * strCustom_Hz = "Horizontal deblocking"; +static const char * strCustom_Hz_Aq = "Horizontal deblocking auto quality"; +static const char * strCustom_Hz_Ch = "Horizontal deblocking chrominance"; + +static const char * strCustom_Vt = "Vertical deblocking"; +static const char * strCustom_Vt_Aq = "Vertical deblocking auto quality"; +static const char * strCustom_Vt_Ch = "Vertical deblocking chrominance"; + +static const char * strCustom_Dr = "Dering filter"; +static const char * strCustom_Dr_Aq = "Dering auto quality"; +static const char * strCustom_Dr_Ch = "Dering chrominance"; + +static const char * strCustom_Al = "Autolevel"; +static const char * strCustom_Al_F = "Autolevel full range"; + +static const char * strCustom_Tn = "Temporal Noise Reducer"; +static const char * strCustom_Tn_S = "Temporal Noise Reducer strength"; + +static const char * strPP_Lin_Blend_Int = "Linear Blend Deinterlacer"; +static const char * strPP_Lin_Int = "Linear Interpolating Deinterlacer"; +static const char * strPP_Cub_Int = "Cubic Interpolating Deinterlacer"; +static const char * strPP_Med_Int = "Median Interpolating Deinterlacer"; +static const char * strPP_FFmpeg_Int = "FFmpeg Interpolating Deinterlacer"; +// end of postproc +// recording +static const char * strRecordingGroup = "Recording"; +static const char * strRecorder = "Recorder"; +static const char * strMencoderArgs = "Mencoder Arguments"; +static const char * strFFMpegArgs = "FFMpeg Arguments"; +static const char * strRecordingFile = "Last Recording Ouput File"; +static const char * strAutoPlayAfterRecording = "Auto Play After Recording"; +static const char * strAutoPlayAfterTime = "Auto Play After Recording Time"; +static const char * strRecordingCopy = "Recording Is Copy"; + +KDE_NO_EXPORT void Settings::applyColorSetting (bool only_changed_ones) { + View *view = static_cast <View *> (m_player->view ()); + if (!view) return; + for (int i = 0; i < int (ColorSetting::last_target); i++) + if (!only_changed_ones || colors[i].color != colors[i].newcolor) { + colors[i].color = colors[i].newcolor; + switch (ColorSetting::Target (i)) { + case ColorSetting::playlist_background: + view->playList()->setPaletteBackgroundColor(colors[i].color); + break; + case ColorSetting::playlist_foreground: + view->playList()->setPaletteForegroundColor(colors[i].color); + break; + case ColorSetting::playlist_active: + view->playList()->setActiveForegroundColor (colors[i].color); + break; + case ColorSetting::console_background: + view->console()->setPaper (QBrush (colors[i].color)); + break; + case ColorSetting::console_foreground: + view->console()->setColor(colors[i].color); + break; + case ColorSetting::video_background: + view->viewer ()->setBackgroundColor (colors[i].color); + break; + case ColorSetting::area_background: + view->viewArea()->setPaletteBackgroundColor(colors[i].color); + break; + case ColorSetting::infowindow_background: + view->infoPanel ()->setPaper (QBrush (colors[i].color)); + break; + case ColorSetting::infowindow_foreground: + view->infoPanel()->setPaletteForegroundColor(colors[i].color); + view->infoPanel ()->setColor (colors[i].color); + break; + default: + ; + } + } + for (int i = 0; i < int (FontSetting::last_target); i++) + if (!only_changed_ones || fonts[i].font != fonts[i].newfont) { + fonts[i].font = fonts[i].newfont; + switch (FontSetting::Target (i)) { + case FontSetting::playlist: + view->playList ()->setFont (fonts[i].font); + break; + case FontSetting::infowindow: + view->infoPanel ()->setFont (fonts[i].font); + break; + default: + ; + } + } +} + +View * Settings::defaultView () { + return static_cast <View *> (m_player->view ()); +} + +KDE_NO_EXPORT void Settings::readConfig () { + m_config->setGroup (strGeneralGroup); + no_intro = m_config->readBoolEntry (strNoIntro, false); + urllist = m_config->readListEntry (strURLList, ';'); + sub_urllist = m_config->readListEntry (strSubURLList, ';'); + prefbitrate = m_config->readNumEntry (strPrefBitRate, 512); + maxbitrate = m_config->readNumEntry (strMaxBitRate, 1024); + volume = m_config->readNumEntry (strVolume, 20); + contrast = m_config->readNumEntry (strContrast, 0); + brightness = m_config->readNumEntry (strBrightness, 0); + hue = m_config->readNumEntry (strHue, 0); + saturation = m_config->readNumEntry (strSaturation, 0); + const QMap <QString, Source*>::const_iterator e = m_player->sources ().end (); + QMap <QString, Source *>::const_iterator i = m_player->sources().begin (); + for (; i != e; ++i) + backends[i.data()->name ()] = m_config->readEntry (i.data()->name ()); + for (int i = 0; i < int (ColorSetting::last_target); i++) + colors[i].newcolor = colors[i].color = m_config->readColorEntry (colors[i].option, &colors[i].color); + for (int i = 0; i < int (FontSetting::last_target); i++) + fonts[i].newfont = fonts[i].font = m_config->readFontEntry (fonts[i].option, &fonts[i].font); + + m_config->setGroup (strMPlayerGroup); + sizeratio = m_config->readBoolEntry (strKeepSizeRatio, true); + remembersize = m_config->readBoolEntry (strRememberSize, true); + autoresize = m_config->readBoolEntry (strAutoResize, true); + docksystray = m_config->readBoolEntry (strDockSysTray, true); + loop = m_config->readBoolEntry (strLoop, false); + framedrop = m_config->readBoolEntry (strFrameDrop, true); + autoadjustvolume = m_config->readBoolEntry (strAdjustVolume, true); + autoadjustcolors = m_config->readBoolEntry (strAdjustColors, true); + mplayerpost090 = m_config->readBoolEntry (strPostMPlayer090, true); + showcnfbutton = m_config->readBoolEntry (strAddConfigButton, true); + showrecordbutton = m_config->readBoolEntry (strAddRecordButton, true); + showbroadcastbutton = m_config->readBoolEntry (strAddBroadcastButton, true); + showplaylistbutton = m_config->readBoolEntry (strAddPlaylistButton, true); + seektime = m_config->readNumEntry (strSeekTime, 10); + dvddevice = m_config->readEntry (strDVDDevice, "/dev/dvd"); + vcddevice = m_config->readEntry (strVCDDevice, "/dev/cdrom"); + videodriver = m_config->readNumEntry (strVoDriver, 0); + audiodriver = m_config->readNumEntry (strAoDriver, 0); + allowhref = m_config->readBoolEntry(strAllowHref, false); + + // recording + m_config->setGroup (strRecordingGroup); + mencoderarguments = m_config->readEntry (strMencoderArgs, "-oac mp3lame -ovc lavc"); + ffmpegarguments = m_config->readEntry (strFFMpegArgs, "-f avi -acodec mp3 -vcodec mpeg4"); + recordfile = m_config->readPathEntry(strRecordingFile, QDir::homeDirPath () + "/record.avi"); + recorder = Recorder (m_config->readNumEntry (strRecorder, int (MEncoder))); + replayoption = ReplayOption (m_config->readNumEntry (strAutoPlayAfterRecording, ReplayFinished)); + replaytime = m_config->readNumEntry (strAutoPlayAfterTime, 60); + recordcopy = m_config->readBoolEntry(strRecordingCopy, true); + + // postproc + m_config->setGroup (strPPGroup); + postprocessing = m_config->readBoolEntry (strPostProcessing, false); + disableppauto = m_config->readBoolEntry (strDisablePPauto, true); + + pp_default = m_config->readBoolEntry (strPP_Default, true); + pp_fast = m_config->readBoolEntry (strPP_Fast, false); + pp_custom = m_config->readBoolEntry (strPP_Custom, false); + // default these to default preset + pp_custom_hz = m_config->readBoolEntry (strCustom_Hz, true); + pp_custom_hz_aq = m_config->readBoolEntry (strCustom_Hz_Aq, true); + pp_custom_hz_ch = m_config->readBoolEntry (strCustom_Hz_Ch, false); + + pp_custom_vt = m_config->readBoolEntry (strCustom_Vt, true); + pp_custom_vt_aq = m_config->readBoolEntry (strCustom_Vt_Aq, true); + pp_custom_vt_ch = m_config->readBoolEntry (strCustom_Vt_Ch, false); + + pp_custom_dr = m_config->readBoolEntry (strCustom_Dr, true); + pp_custom_dr_aq = m_config->readBoolEntry (strCustom_Dr_Aq, true); + pp_custom_dr_ch = m_config->readBoolEntry (strCustom_Dr_Ch, false); + + pp_custom_al = m_config->readBoolEntry (strCustom_Al, true); + pp_custom_al_f = m_config->readBoolEntry (strCustom_Al_F, false); + + pp_custom_tn = m_config->readBoolEntry (strCustom_Tn, true); + pp_custom_tn_s = m_config->readNumEntry (strCustom_Tn_S, 0); + + pp_lin_blend_int = m_config->readBoolEntry (strPP_Lin_Blend_Int, false); + pp_lin_int = m_config->readBoolEntry (strPP_Lin_Int, false); + pp_cub_int = m_config->readBoolEntry (strPP_Cub_Int, false); + pp_med_int = m_config->readBoolEntry (strPP_Med_Int, false); + pp_ffmpeg_int = m_config->readBoolEntry (strPP_FFmpeg_Int, false); + + for (PreferencesPage * p = pagelist; p; p = p->next) + p->read (m_config); + emit configChanged (); +} + +KDE_NO_EXPORT bool Settings::createDialog () { + if (configdialog) return false; + configdialog = new Preferences (m_player, this); + int id = 0; + const PartBase::ProcessMap::const_iterator e = m_player->players ().end (); + for (PartBase::ProcessMap::const_iterator i = m_player->players ().begin(); i != e; ++i) { + Process * p = i.data (); + if (p->supports ("urlsource")) + configdialog->m_SourcePageURL->backend->insertItem (p->menuName ().remove (QChar ('&')), id++); + } + connect (configdialog, SIGNAL (okClicked ()), + this, SLOT (okPressed ())); + connect (configdialog, SIGNAL (applyClicked ()), + this, SLOT (okPressed ())); + if (KApplication::kApplication()) + connect (configdialog, SIGNAL (helpClicked ()), + this, SLOT (getHelp ())); + return true; +} + +void Settings::addPage (PreferencesPage * page) { + for (PreferencesPage * p = pagelist; p; p = p->next) + if (p == page) + return; + page->read (m_config); + if (configdialog) { + configdialog->addPrefPage (page); + page->sync (false); + } + page->next = pagelist; + pagelist = page; +} + +void Settings::removePage (PreferencesPage * page) { + if (configdialog) + configdialog->removePrefPage (page); + PreferencesPage * prev = 0L; + for (PreferencesPage * p = pagelist; p; prev = p, p = p->next) + if (p == page) { + if (prev) + prev->next = p->next; + else + pagelist = p->next; + break; + } +} + +void Settings::show (const char * pagename) { + bool created = createDialog (); + configdialog->m_GeneralPageGeneral->keepSizeRatio->setChecked (sizeratio); + configdialog->m_GeneralPageGeneral->autoResize->setChecked (autoresize); + configdialog->m_GeneralPageGeneral->sizesChoice->setButton (remembersize ? 0 : 1); + configdialog->m_GeneralPageGeneral->dockSysTray->setChecked (docksystray); + configdialog->m_GeneralPageGeneral->loop->setChecked (loop); + configdialog->m_GeneralPageGeneral->framedrop->setChecked (framedrop); + configdialog->m_GeneralPageGeneral->adjustvolume->setChecked (autoadjustvolume); + configdialog->m_GeneralPageGeneral->adjustcolors->setChecked (autoadjustcolors); + //configdialog->m_GeneralPageGeneral->autoHideSlider->setChecked (autohideslider); + configdialog->m_GeneralPageGeneral->showConfigButton->setChecked (showcnfbutton); + configdialog->m_GeneralPageGeneral->showPlaylistButton->setChecked (showplaylistbutton); + configdialog->m_GeneralPageGeneral->showRecordButton->setChecked (showrecordbutton); + configdialog->m_GeneralPageGeneral->showBroadcastButton->setChecked (showbroadcastbutton); + configdialog->m_GeneralPageGeneral->seekTime->setValue(seektime); + for (int i = 0; i < int (ColorSetting::last_target); i++) + colors[i].newcolor = colors[i].color; + for (int i = 0; i < int (FontSetting::last_target); i++) + fonts[i].newfont = fonts[i].font; + configdialog->m_SourcePageURL->urllist->clear (); + configdialog->m_SourcePageURL->urllist->insertStringList (urllist); + configdialog->m_SourcePageURL->urllist->setCurrentText (m_player->source ()->url ().prettyURL ()); + configdialog->m_SourcePageURL->sub_urllist->clear (); + configdialog->m_SourcePageURL->sub_urllist->insertStringList (sub_urllist); + configdialog->m_SourcePageURL->sub_urllist->setCurrentText (m_player->source ()->subUrl ().prettyURL ()); + configdialog->m_SourcePageURL->changed = false; + configdialog->m_SourcePageURL->prefBitRate->setText (QString::number (prefbitrate)); + configdialog->m_SourcePageURL->maxBitRate->setText (QString::number (maxbitrate)); + + configdialog->m_GeneralPageOutput->videoDriver->setCurrentItem (videodriver); + configdialog->m_GeneralPageOutput->audioDriver->setCurrentItem (audiodriver); + configdialog->m_SourcePageURL->backend->setCurrentItem (configdialog->m_SourcePageURL->backend->findItem (backends["urlsource"])); + int id = 0; + const PartBase::ProcessMap::const_iterator e = m_player->players ().end (); + for (PartBase::ProcessMap::const_iterator i = m_player->players ().begin(); i != e; ++i) { + Process * p = i.data (); + if (p->supports ("urlsource")) { + if (backends["urlsource"] == QString (p->name())) + configdialog->m_SourcePageURL->backend->setCurrentItem (id); + id++; + } + } + configdialog->m_SourcePageURL->allowhref->setChecked (allowhref); + + // postproc + configdialog->m_OPPagePostproc->postProcessing->setChecked (postprocessing); + configdialog->m_OPPagePostproc->disablePPauto->setChecked (disableppauto); + configdialog->m_OPPagePostproc->PostprocessingOptions->setEnabled (postprocessing); + + configdialog->m_OPPagePostproc->defaultPreset->setChecked (pp_default); + configdialog->m_OPPagePostproc->fastPreset->setChecked (pp_fast); + configdialog->m_OPPagePostproc->customPreset->setChecked (pp_custom); + + configdialog->m_OPPagePostproc->HzDeblockFilter->setChecked (pp_custom_hz); + configdialog->m_OPPagePostproc->HzDeblockAQuality->setChecked (pp_custom_hz_aq); + configdialog->m_OPPagePostproc->HzDeblockCFiltering->setChecked (pp_custom_hz_ch); + + configdialog->m_OPPagePostproc->VtDeblockFilter->setChecked (pp_custom_vt); + configdialog->m_OPPagePostproc->VtDeblockAQuality->setChecked (pp_custom_vt_aq); + configdialog->m_OPPagePostproc->VtDeblockCFiltering->setChecked (pp_custom_vt_ch); + + configdialog->m_OPPagePostproc->DeringFilter->setChecked (pp_custom_dr); + configdialog->m_OPPagePostproc->DeringAQuality->setChecked (pp_custom_dr_aq); + configdialog->m_OPPagePostproc->DeringCFiltering->setChecked (pp_custom_dr_ch); + + configdialog->m_OPPagePostproc->AutolevelsFilter->setChecked (pp_custom_al); + configdialog->m_OPPagePostproc->AutolevelsFullrange->setChecked (pp_custom_al_f); + configdialog->m_OPPagePostproc->TmpNoiseFilter->setChecked (pp_custom_tn); + //configdialog->m_OPPagePostproc->TmpNoiseSlider->setValue (pp_custom_tn_s); + + configdialog->m_OPPagePostproc->LinBlendDeinterlacer->setChecked (pp_lin_blend_int); + configdialog->m_OPPagePostproc->LinIntDeinterlacer->setChecked (pp_lin_int); + configdialog->m_OPPagePostproc->CubicIntDeinterlacer->setChecked (pp_cub_int); + configdialog->m_OPPagePostproc->MedianDeinterlacer->setChecked (pp_med_int); + configdialog->m_OPPagePostproc->FfmpegDeinterlacer->setChecked (pp_ffmpeg_int); + // recording + configdialog->m_RecordPage->url->lineEdit()->setText (recordfile); + configdialog->m_RecordPage->replay->setButton (int (replayoption)); + configdialog->m_RecordPage->recorder->setButton (int (recorder)); + configdialog->m_RecordPage->replayClicked (int (replayoption)); + configdialog->m_RecordPage->recorderClicked (int (recorder)); + configdialog->m_RecordPage->replaytime->setText (QString::number (replaytime)); + configdialog->m_MEncoderPage->arguments->setText (mencoderarguments); + configdialog->m_MEncoderPage->format->setButton (recordcopy ? 0 : 1); + configdialog->m_MEncoderPage->formatClicked (recordcopy ? 0 : 1); + configdialog->m_FFMpegPage->arguments->setText (ffmpegarguments); + + //dynamic stuff + for (PreferencesPage * p = pagelist; p; p = p->next) + p->sync (false); + //\dynamic stuff + if (pagename) + configDialog ()->setPage (pagename); + if (created) + configdialog->resize (configdialog->minimumSize ()); + configdialog->show (); +} + +void Settings::writeConfig () { + m_config->setGroup (strGeneralGroup); + m_config->writeEntry (strURLList, urllist, ';'); + m_config->writeEntry (strSubURLList, sub_urllist, ';'); + m_config->writeEntry (strPrefBitRate, prefbitrate); + m_config->writeEntry (strMaxBitRate, maxbitrate); + m_config->writeEntry (strVolume, volume); + m_config->writeEntry (strContrast, contrast); + m_config->writeEntry (strBrightness, brightness); + m_config->writeEntry (strHue, hue); + m_config->writeEntry (strSaturation, saturation); + const QMap<QString,QString>::iterator b_end = backends.end (); + for (QMap<QString,QString>::iterator i = backends.begin(); i != b_end; ++i) + m_config->writeEntry (i.key (), i.data ()); + for (int i = 0; i < int (ColorSetting::last_target); i++) + m_config->writeEntry (colors[i].option, colors[i].color); + for (int i = 0; i < int (FontSetting::last_target); i++) + m_config->writeEntry (fonts[i].option, fonts[i].font); + m_config->setGroup (strMPlayerGroup); + m_config->writeEntry (strKeepSizeRatio, sizeratio); + m_config->writeEntry (strAutoResize, autoresize); + m_config->writeEntry (strRememberSize, remembersize); + m_config->writeEntry (strDockSysTray, docksystray); + m_config->writeEntry (strLoop, loop); + m_config->writeEntry (strFrameDrop, framedrop); + m_config->writeEntry (strAdjustVolume, autoadjustvolume); + m_config->writeEntry (strAdjustColors, autoadjustcolors); + m_config->writeEntry (strSeekTime, seektime); + m_config->writeEntry (strVoDriver, videodriver); + m_config->writeEntry (strAoDriver, audiodriver); + m_config->writeEntry (strAllowHref, allowhref); + m_config->writeEntry (strAddConfigButton, showcnfbutton); + m_config->writeEntry (strAddPlaylistButton, showplaylistbutton); + m_config->writeEntry (strAddRecordButton, showrecordbutton); + m_config->writeEntry (strAddBroadcastButton, showbroadcastbutton); + + m_config->writeEntry (strDVDDevice, dvddevice); + m_config->writeEntry (strVCDDevice, vcddevice); + + //postprocessing stuff + m_config->setGroup (strPPGroup); + m_config->writeEntry (strPostProcessing, postprocessing); + m_config->writeEntry (strDisablePPauto, disableppauto); + m_config->writeEntry (strPP_Default, pp_default); + m_config->writeEntry (strPP_Fast, pp_fast); + m_config->writeEntry (strPP_Custom, pp_custom); + + m_config->writeEntry (strCustom_Hz, pp_custom_hz); + m_config->writeEntry (strCustom_Hz_Aq, pp_custom_hz_aq); + m_config->writeEntry (strCustom_Hz_Ch, pp_custom_hz_ch); + + m_config->writeEntry (strCustom_Vt, pp_custom_vt); + m_config->writeEntry (strCustom_Vt_Aq, pp_custom_vt_aq); + m_config->writeEntry (strCustom_Vt_Ch, pp_custom_vt_ch); + + m_config->writeEntry (strCustom_Dr, pp_custom_dr); + m_config->writeEntry (strCustom_Dr_Aq, pp_custom_vt_aq); + m_config->writeEntry (strCustom_Dr_Ch, pp_custom_vt_ch); + + m_config->writeEntry (strCustom_Al, pp_custom_al); + m_config->writeEntry (strCustom_Al_F, pp_custom_al_f); + + m_config->writeEntry (strCustom_Tn, pp_custom_tn); + m_config->writeEntry (strCustom_Tn_S, pp_custom_tn_s); + + m_config->writeEntry (strPP_Lin_Blend_Int, pp_lin_blend_int); + m_config->writeEntry (strPP_Lin_Int, pp_lin_int); + m_config->writeEntry (strPP_Cub_Int, pp_cub_int); + m_config->writeEntry (strPP_Med_Int, pp_med_int); + m_config->writeEntry (strPP_FFmpeg_Int, pp_ffmpeg_int); + + // recording + m_config->setGroup (strRecordingGroup); + m_config->writePathEntry (strRecordingFile, recordfile); + m_config->writeEntry (strAutoPlayAfterRecording, int (replayoption)); + m_config->writeEntry (strAutoPlayAfterTime, replaytime); + m_config->writeEntry (strRecorder, int (recorder)); + m_config->writeEntry (strRecordingCopy, recordcopy); + m_config->writeEntry (strMencoderArgs, mencoderarguments); + m_config->writeEntry (strFFMpegArgs, ffmpegarguments); + + //dynamic stuff + for (PreferencesPage * p = pagelist; p; p = p->next) + p->write (m_config); + //\dynamic stuff + m_config->sync (); +} + +void Settings::okPressed () { + bool urlchanged = configdialog->m_SourcePageURL->changed; + bool playerchanged = false; + if (urlchanged) { + if (configdialog->m_SourcePageURL->url->url ().isEmpty ()) + urlchanged = false; + else { + if (KURL::fromPathOrURL (configdialog->m_SourcePageURL->url->url ()).isLocalFile () || + KURL::isRelativeURL (configdialog->m_SourcePageURL->url->url ())) { + QFileInfo fi (configdialog->m_SourcePageURL->url->url ()); + int hpos = configdialog->m_SourcePageURL->url->url ().findRev ('#'); + QString xine_directives (""); + while (!fi.exists () && hpos > -1) { + xine_directives = configdialog->m_SourcePageURL->url->url ().mid (hpos); + fi.setFile (configdialog->m_SourcePageURL->url->url ().left (hpos)); + hpos = configdialog->m_SourcePageURL->url->url ().findRev ('#', hpos-1); + } + if (!fi.exists ()) { + urlchanged = false; + KMessageBox::error (m_player->view (), i18n ("File %1 does not exist.").arg (configdialog->m_SourcePageURL->url->url ()), i18n ("Error")); + } else + configdialog->m_SourcePageURL->url->setURL (fi.absFilePath () + xine_directives); + } + if (urlchanged && + !configdialog->m_SourcePageURL->sub_url->url ().isEmpty () && + (KURL::fromPathOrURL (configdialog->m_SourcePageURL->sub_url->url ()).isLocalFile () || + KURL::isRelativeURL (configdialog->m_SourcePageURL->sub_url->url ()))) { + QFileInfo sfi (configdialog->m_SourcePageURL->sub_url->url ()); + if (!sfi.exists ()) { + KMessageBox::error (m_player->view (), i18n ("Sub title file %1 does not exist.").arg (configdialog->m_SourcePageURL->sub_url->url ()), i18n ("Error")); + configdialog->m_SourcePageURL->sub_url->setURL (QString ()); + } else + configdialog->m_SourcePageURL->sub_url->setURL (sfi.absFilePath ()); + } + } + } + if (urlchanged) { + KURL url = KURL::fromPathOrURL (configdialog->m_SourcePageURL->url->url ()); + m_player->setURL (url); + if (urllist.find (url.prettyURL ()) == urllist.end ()) + configdialog->m_SourcePageURL->urllist->insertItem (url.prettyURL (), 0); + KURL sub_url = KURL::fromPathOrURL (configdialog->m_SourcePageURL->sub_url->url ()); + if (sub_urllist.find (sub_url.prettyURL ()) == sub_urllist.end ()) + configdialog->m_SourcePageURL->sub_urllist->insertItem (sub_url.prettyURL (), 0); + } + urllist.clear (); + for (int i = 0; i < configdialog->m_SourcePageURL->urllist->count () && i < 20; ++i) + // damnit why don't maxCount and setDuplicatesEnabled(false) work :( + // and why can I put a qstringlist in it, but cannot get it out of it again.. + if (!configdialog->m_SourcePageURL->urllist->text (i).isEmpty ()) + urllist.push_back (configdialog->m_SourcePageURL->urllist->text (i)); + sub_urllist.clear (); + for (int i = 0; i < configdialog->m_SourcePageURL->sub_urllist->count () && i < 20; ++i) + if (!configdialog->m_SourcePageURL->sub_urllist->text (i).isEmpty ()) + sub_urllist.push_back (configdialog->m_SourcePageURL->sub_urllist->text (i)); + prefbitrate = configdialog->m_SourcePageURL->prefBitRate->text ().toInt (); + maxbitrate = configdialog->m_SourcePageURL->maxBitRate->text ().toInt (); + sizeratio = configdialog->m_GeneralPageGeneral->keepSizeRatio->isChecked (); + autoresize = configdialog->m_GeneralPageGeneral->autoResize->isChecked (); + remembersize=!configdialog->m_GeneralPageGeneral->sizesChoice->selectedId(); + docksystray = configdialog->m_GeneralPageGeneral->dockSysTray->isChecked (); + loop = configdialog->m_GeneralPageGeneral->loop->isChecked (); + framedrop = configdialog->m_GeneralPageGeneral->framedrop->isChecked (); + autoadjustvolume = configdialog->m_GeneralPageGeneral->adjustvolume->isChecked (); + autoadjustcolors = configdialog->m_GeneralPageGeneral->adjustcolors->isChecked (); + showcnfbutton = configdialog->m_GeneralPageGeneral->showConfigButton->isChecked (); + showplaylistbutton = configdialog->m_GeneralPageGeneral->showPlaylistButton->isChecked (); + showrecordbutton = configdialog->m_GeneralPageGeneral->showRecordButton->isChecked (); + showbroadcastbutton = configdialog->m_GeneralPageGeneral->showBroadcastButton->isChecked (); + seektime = configdialog->m_GeneralPageGeneral->seekTime->value(); + + videodriver = configdialog->m_GeneralPageOutput->videoDriver->currentItem(); + audiodriver = configdialog->m_GeneralPageOutput->audioDriver->currentItem(); + if (!strcmp (m_player->source()->name (), "urlsource")) { + int backend = configdialog->m_SourcePageURL->backend->currentItem (); + const PartBase::ProcessMap::const_iterator e = m_player->players ().end(); + for (PartBase::ProcessMap::const_iterator i = m_player->players ().begin(); backend >=0 && i != e; ++i) { + Process * proc = i.data (); + if (proc->supports ("urlsource") && backend-- == 0) { + backends["urlsource"] = proc->name (); + if (proc != m_player->process ()) { + m_player->setProcess (proc->name ()); + playerchanged = true; + } + } + } + } + allowhref = configdialog->m_SourcePageURL->allowhref->isChecked (); + //postproc + postprocessing = configdialog->m_OPPagePostproc->postProcessing->isChecked(); + disableppauto = configdialog->m_OPPagePostproc->disablePPauto->isChecked(); + pp_default = configdialog->m_OPPagePostproc->defaultPreset->isChecked(); + pp_fast = configdialog->m_OPPagePostproc->fastPreset->isChecked(); + pp_custom = configdialog->m_OPPagePostproc->customPreset->isChecked(); + + pp_custom_hz = configdialog->m_OPPagePostproc->HzDeblockFilter->isChecked(); + pp_custom_hz_aq = configdialog->m_OPPagePostproc->HzDeblockAQuality->isChecked(); + pp_custom_hz_ch = configdialog->m_OPPagePostproc->HzDeblockCFiltering->isChecked(); + + pp_custom_vt = configdialog->m_OPPagePostproc->VtDeblockFilter->isChecked(); + pp_custom_vt_aq = configdialog->m_OPPagePostproc->VtDeblockAQuality->isChecked(); + pp_custom_vt_ch = configdialog->m_OPPagePostproc->VtDeblockCFiltering->isChecked(); + + pp_custom_dr = configdialog->m_OPPagePostproc->DeringFilter->isChecked(); + pp_custom_dr_aq = configdialog->m_OPPagePostproc->DeringAQuality->isChecked(); + pp_custom_dr_ch = configdialog->m_OPPagePostproc->DeringCFiltering->isChecked(); + + pp_custom_al = configdialog->m_OPPagePostproc->AutolevelsFilter->isChecked(); + pp_custom_al_f = configdialog->m_OPPagePostproc->AutolevelsFullrange->isChecked(); + + pp_custom_tn = configdialog->m_OPPagePostproc->TmpNoiseFilter->isChecked(); + pp_custom_tn_s = 0; // gotta fix this later + //pp_custom_tn_s = configdialog->m_OPPagePostproc->TmpNoiseSlider->value(); + + pp_lin_blend_int = configdialog->m_OPPagePostproc->LinBlendDeinterlacer->isChecked(); + pp_lin_int = configdialog->m_OPPagePostproc->LinIntDeinterlacer->isChecked(); + pp_cub_int = configdialog->m_OPPagePostproc->CubicIntDeinterlacer->isChecked(); + pp_med_int = configdialog->m_OPPagePostproc->MedianDeinterlacer->isChecked(); + pp_ffmpeg_int = configdialog->m_OPPagePostproc->FfmpegDeinterlacer->isChecked(); + // recording +#if (QT_VERSION < 0x030200) + recorder = Recorder (configdialog->m_RecordPage->recorder->id (configdialog->m_RecordPage->recorder->selected ())); +#else + recorder = Recorder (configdialog->m_RecordPage->recorder->selectedId ()); +#endif + replaytime = configdialog->m_RecordPage->replaytime->text ().toInt (); + configdialog->m_RecordPage->replaytime->setText (QString::number (replaytime)); + recordfile = configdialog->m_RecordPage->url->lineEdit()->text (); + mencoderarguments = configdialog->m_MEncoderPage->arguments->text (); + ffmpegarguments = configdialog->m_FFMpegPage->arguments->text (); +#if (QT_VERSION < 0x030200) + recordcopy = !configdialog->m_MEncoderPage->format->id (configdialog->m_MEncoderPage->format->selected ()); +#else + recordcopy = !configdialog->m_MEncoderPage->format->selectedId (); +#endif + + //dynamic stuff + for (PreferencesPage * p = pagelist; p; p = p->next) + p->sync (true); + //\dynamic stuff + + writeConfig (); + emit configChanged (); + + if (urlchanged || playerchanged) { + m_player->sources () ["urlsource"]->setSubURL + (KURL(configdialog->m_SourcePageURL->sub_url->url())); + m_player->openURL (KURL::fromPathOrURL (configdialog->m_SourcePageURL->url->url ())); + m_player->source ()->setSubURL (KURL::fromPathOrURL (configdialog->m_SourcePageURL->sub_url->url ())); + } +} + +KDE_NO_EXPORT void Settings::getHelp () { + KApplication::kApplication()->invokeBrowser ("man:/mplayer"); +} + +#include "kmplayerconfig.moc" + diff --git a/src/kmplayerconfig.h b/src/kmplayerconfig.h new file mode 100644 index 0000000..784c1c6 --- /dev/null +++ b/src/kmplayerconfig.h @@ -0,0 +1,204 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef _KMPLAYERCONFIG_H_ +#define _KMPLAYERCONFIG_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qobject.h> +#include <qstringlist.h> +#include <qmap.h> + +#include <kurl.h> + +class KConfig; + +namespace KMPlayer { + +class PartBase; +class Preferences; +class View; + +class OutputDriver { +public: + const char * driver; + const QString description; +}; + +class ColorSetting { +public: + QString title; + QString option; + QColor color; + QColor newcolor; + enum Target { + playlist_background = 0, playlist_foreground, playlist_active, + console_background, console_foreground, + video_background, area_background, + infowindow_background, infowindow_foreground, + last_target + } target; +}; + +class FontSetting { +public: + QString title; + QString option; // for ini file + QFont font; + QFont newfont; + enum Target { + playlist, infowindow, last_target + } target; +}; + +template <class T> +struct Deleter { + void operator ()(T * t) { + delete t; + } +}; + +/* + * Base class for all dynamic preferance pages + */ +class KMPLAYER_EXPORT PreferencesPage { +public: + virtual ~PreferencesPage () {} + virtual void write (KConfig *) = 0; + virtual void read (KConfig *) = 0; + virtual void sync (bool fromUI) = 0; + virtual void prefLocation (QString & item, QString & icon, QString & tab) = 0; + virtual QFrame * prefPage (QWidget * parent) = 0; + PreferencesPage * next; +}; + +/* + * Class for storing all actual settings and reading/writing them + */ +class KMPLAYER_EXPORT Settings : public QObject { + Q_OBJECT +public: + Settings (PartBase *, KConfig * part); + ~Settings (); + bool createDialog () KDE_NO_EXPORT; + void show (const char * pagename = 0L); + void addPage (PreferencesPage *); + void removePage (PreferencesPage *); + void applyColorSetting (bool only_changed_ones); + Preferences *configDialog() const { return configdialog; } + View * defaultView (); + KConfig * kconfig () { return m_config; } + + QStringList urllist; + QStringList sub_urllist; + int volume; + int contrast; + int brightness; + int hue; + int saturation; + int prefbitrate; + int maxbitrate; + bool usearts : 1; + bool no_intro : 1; + bool sizeratio : 1; + bool remembersize : 1; + bool autoresize : 1; + bool docksystray : 1; + bool loop : 1; + bool framedrop : 1; + bool autoadjustvolume : 1; + bool autoadjustcolors : 1; + bool showcnfbutton : 1; + bool showplaylistbutton : 1; + bool showrecordbutton : 1; + bool showbroadcastbutton : 1; + bool autohideslider : 1; + bool mplayerpost090 : 1; + bool allowhref : 1; +// postproc thingies + bool postprocessing : 1; + bool disableppauto : 1; + bool pp_default : 1; // -vf pp=de + bool pp_fast : 1; // -vf pp=fa + bool pp_custom : 1; // coming up + + bool pp_custom_hz : 1; // horizontal deblocking + bool pp_custom_hz_aq : 1; // - autoquality + bool pp_custom_hz_ch : 1; // - chrominance + + bool pp_custom_vt : 1; // vertical deblocking + bool pp_custom_vt_aq : 1; // - autoquality + bool pp_custom_vt_ch : 1; // - chrominance + + bool pp_custom_dr : 1; // dering filter + bool pp_custom_dr_aq : 1; // - autoquality + bool pp_custom_dr_ch : 1; // - chrominance + + bool pp_custom_al : 1; // pp=al + bool pp_custom_al_f : 1;// - fullrange + + bool pp_custom_tn : 1; // pp=tn + int pp_custom_tn_s : 1; // - noise reducer strength (1 <= x <= 3) + + bool pp_lin_blend_int : 1; // linear blend deinterlacer + bool pp_lin_int : 1; // - interpolating - + bool pp_cub_int : 1; // cubic - - + bool pp_med_int : 1; // median interlacer + bool pp_ffmpeg_int : 1; // ffmpeg interlacer +// end of postproc + // recording + bool recordcopy : 1; + enum Recorder { MEncoder = 0, FFMpeg, MPlayerDumpstream }; + Recorder recorder; + enum ReplayOption { ReplayNo = 0, ReplayFinished, ReplayAfter }; + ReplayOption replayoption; + int replaytime; + QString mencoderarguments; + QString ffmpegarguments; + QString recordfile; + int seektime; + int videodriver; + int audiodriver; + OutputDriver * audiodrivers; + OutputDriver * videodrivers; + ColorSetting colors [ColorSetting::last_target]; + FontSetting fonts [FontSetting::last_target]; + QString dvddevice; + QString vcddevice; + QMap <QString, QString> backends; + PreferencesPage * pagelist; +signals: + void configChanged (); +public slots: + void readConfig () KDE_NO_EXPORT; + void writeConfig (); +private slots: + void okPressed (); + void getHelp (); +private: + Preferences * configdialog; + KConfig * m_config; + PartBase * m_player; +}; + +} // namespace + +#endif //_KMPLAYERCONFIG_H_ diff --git a/src/kmplayercontrolpanel.cpp b/src/kmplayercontrolpanel.cpp new file mode 100644 index 0000000..ce5d617 --- /dev/null +++ b/src/kmplayercontrolpanel.cpp @@ -0,0 +1,703 @@ +/** + * Copyright (C) 2005 by Koos Vriezen <koos ! vriezen ? gmail ! com> + * + * 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 <qlayout.h> +#include <qpixmap.h> +#include <qslider.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qpainter.h> +#include <qstringlist.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kdebug.h> + +#include "kmplayerview.h" +#include "kmplayercontrolpanel.h" +#include "kmplayersource.h" + +static const int button_height_with_slider = 15; +static const int button_height_only_buttons = 11; +extern const char * normal_window_xpm[]; +extern const char * playlist_xpm[]; +#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, + " ", + " ", + "...........", + " ......... ", + " ....... ", + " ..... ", + " ... ", + " . "}; + +const char * playlist_xpm[] = { + "8 9 2 1", + " c None", + xpm_fg_color, + " ", + " ", + "........", + "........", + " ", + " ", + "........", + "........", + " "}; + +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 QPushButton * ctrlButton (QWidget * w, QBoxLayout * l, const char ** p, int key = 0) { + QPushButton * b = new QPushButton (QIconSet (QPixmap(p)), QString (), w); + b->setFocusPolicy (QWidget::NoFocus); + b->setFlat (true); + if (key) + b->setAccel (QKeySequence (key)); + l->addWidget (b); + return b; +} + +KDE_NO_CDTOR_EXPORT +KMPlayerMenuButton::KMPlayerMenuButton (QWidget * parent, QBoxLayout * l, const char ** p, int key) + : QPushButton (QIconSet (QPixmap(p)), QString (), parent, "kde_kmplayer_control_button") { + setFocusPolicy (QWidget::NoFocus); + setFlat (true); + if (key) + setAccel (QKeySequence (key)); + l->addWidget (this); +} + +KDE_NO_EXPORT void KMPlayerMenuButton::enterEvent (QEvent *) { + emit mouseEntered (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerPopupMenu::KMPlayerPopupMenu (QWidget * parent) + : KPopupMenu (parent, "kde_kmplayer_popupmenu") {} + +KDE_NO_EXPORT void KMPlayerPopupMenu::leaveEvent (QEvent *) { + emit mouseLeft (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT VolumeBar::VolumeBar (QWidget * parent, View * view) + : QWidget (parent), m_view (view), m_value (100) { + setSizePolicy( QSizePolicy (QSizePolicy::Minimum, QSizePolicy::Fixed)); + setMinimumSize (QSize (51, button_height_only_buttons + 2)); + QToolTip::add (this, i18n ("Volume is %1").arg (m_value)); +} + +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; + QToolTip::remove (this); + QToolTip::add (this, i18n ("Volume is %1").arg (m_value)); + repaint (true); + 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 = paletteForegroundColor (); + p.setPen (color); + int w = width () - 6; + int vx = m_value * w / 100; + p.fillRect (3, 3, vx, 7, color); + p.drawRect (vx + 3, 3, w - vx, 7); + p.end (); + //kdDebug () << "w=" << w << " vx=" << vx << endl; +} + +void VolumeBar::mousePressEvent (QMouseEvent * e) { + setValue (100 * (e->x () - 3) / (width () - 6)); + e->accept (); +} + +void VolumeBar::mouseMoveEvent (QMouseEvent * e) { + setValue (100 * (e->x () - 3) / (width () - 6)); + 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) { + m_buttonbox = new QHBoxLayout (this, 5, 4); + QColor c = paletteForegroundColor (); + strncpy (xpm_fg_color, QString().sprintf(". c #%02x%02x%02x", c.red(), c.green(),c.blue()).ascii(), 31); + xpm_fg_color[31] = 0; + m_buttons[button_config] = new KMPlayerMenuButton (this, m_buttonbox, config_xpm); + m_buttons[button_playlist] = ctrlButton (this, m_buttonbox, playlist_xpm); + m_buttons[button_back] = ctrlButton (this, m_buttonbox, back_xpm); + m_buttons[button_play] = ctrlButton(this, m_buttonbox, play_xpm, Qt::Key_R); + m_buttons[button_forward] = ctrlButton (this, m_buttonbox, forward_xpm); + m_buttons[button_stop] = ctrlButton(this, m_buttonbox, stop_xpm, Qt::Key_S); + m_buttons[button_pause]=ctrlButton(this, m_buttonbox, pause_xpm, Qt::Key_P); + m_buttons[button_record] = ctrlButton (this, m_buttonbox, record_xpm); + m_buttons[button_broadcast] = ctrlButton (this, m_buttonbox, broadcast_xpm); + m_buttons[button_language] = new KMPlayerMenuButton (this, m_buttonbox, language_xpm); + m_buttons[button_red] = ctrlButton (this, m_buttonbox, red_xpm); + m_buttons[button_green] = ctrlButton (this, m_buttonbox, green_xpm); + m_buttons[button_yellow] = ctrlButton (this, m_buttonbox, yellow_xpm); + m_buttons[button_blue] = ctrlButton (this, m_buttonbox, blue_xpm); + m_buttons[button_play]->setToggleButton (true); + m_buttons[button_stop]->setToggleButton (true); + m_buttons[button_record]->setToggleButton (true); + m_buttons[button_broadcast]->setToggleButton (true); + m_posSlider = new QSlider (0, 100, 1, 0, Qt::Horizontal, this); + m_posSlider->setEnabled (false); + m_buttonbox->addWidget (m_posSlider); + setupPositionSlider (true); + m_volume = new VolumeBar (this, m_view); + m_buttonbox->addWidget (m_volume); + m_popupMenu = new KMPlayerPopupMenu (this); + m_playerMenu = new KMPlayerPopupMenu (this); + m_popupMenu->insertItem (i18n ("&Play with"), m_playerMenu, menu_player); + m_bookmarkMenu = new KMPlayerPopupMenu (this); + m_popupMenu->insertItem (i18n("&Bookmarks"), m_bookmarkMenu, menu_bookmark); + m_popupMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("konsole"), KIcon::Small, 0, true), i18n ("Con&sole"), menu_video); + m_popupMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("player_playlist"), KIcon::Small, 0, true), i18n ("Play&list"), menu_playlist); + m_zoomMenu = new KMPlayerPopupMenu (this); + m_zoomMenu->insertItem (i18n ("50%"), menu_zoom50); + m_zoomMenu->insertItem (i18n ("100%"), menu_zoom100); + m_zoomMenu->insertItem (i18n ("150%"), menu_zoom150); + m_popupMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("viewmag"), KIcon::Small, 0, false), i18n ("&Zoom"), m_zoomMenu, menu_zoom); + m_popupMenu->insertItem (KGlobal::iconLoader()->loadIconSet (QString ("window_fullscreen"), KIcon::Small, 0, true), i18n ("&Full Screen"), menu_fullscreen); + m_popupMenu->setAccel (QKeySequence (Qt::Key_F), menu_fullscreen); + m_popupMenu->insertSeparator (); + m_colorMenu = new KMPlayerPopupMenu (this); + m_languageMenu = new KMPlayerPopupMenu (this); + m_audioMenu = new KMPlayerPopupMenu (this); + m_subtitleMenu = new KMPlayerPopupMenu (this); + m_languageMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("mime-sound"), KIcon::Small, 0, true), i18n ("&Audio languages"), m_audioMenu); + m_languageMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("view_text"), KIcon::Small, 0, true), i18n ("&Subtitles"), m_subtitleMenu); + QLabel * label = new QLabel (i18n ("Contrast:"), m_colorMenu); + m_colorMenu->insertItem (label); + m_contrastSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, m_colorMenu); + m_colorMenu->insertItem (m_contrastSlider); + label = new QLabel (i18n ("Brightness:"), m_colorMenu); + m_colorMenu->insertItem (label); + m_brightnessSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, m_colorMenu); + m_colorMenu->insertItem (m_brightnessSlider); + label = new QLabel (i18n ("Hue:"), m_colorMenu); + m_colorMenu->insertItem (label); + m_hueSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, m_colorMenu); + m_colorMenu->insertItem (m_hueSlider); + label = new QLabel (i18n ("Saturation:"), m_colorMenu); + m_colorMenu->insertItem (label); + m_saturationSlider = new QSlider (-100, 100, 10, 0, Qt::Horizontal, m_colorMenu); + m_colorMenu->insertItem (m_saturationSlider); + m_popupMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("colorize"), KIcon::Small, 0, true), i18n ("Co&lors"), m_colorMenu); + m_popupMenu->insertSeparator (); + m_popupMenu->insertItem (KGlobal::iconLoader ()->loadIconSet (QString ("configure"), KIcon::Small, 0, true), i18n ("&Configure KMPlayer..."), menu_config); + 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 (m_popupMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); + connect (m_playerMenu, SIGNAL (mouseLeft ()), this, SLOT(menuMouseLeft ())); + connect (m_zoomMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); + connect (m_colorMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); + connect (m_languageMenu, SIGNAL(mouseLeft ()), this, SLOT(menuMouseLeft())); + connect (m_subtitleMenu, SIGNAL(mouseLeft ()), this, SLOT(menuMouseLeft())); + connect (m_audioMenu, SIGNAL (mouseLeft ()), this, SLOT (menuMouseLeft ())); +} + +KDE_NO_EXPORT void ControlPanel::setPalette (const QPalette & pal) { + QWidget::setPalette (pal); + QColor c = paletteForegroundColor (); + strncpy (xpm_fg_color, QString().sprintf(". c #%02x%02x%02x", c.red(), c.green(),c.blue()).ascii(), 31); + xpm_fg_color[31] = 0; + m_buttons[button_config]->setIconSet (QIconSet (QPixmap (config_xpm))); + m_buttons[button_playlist]->setIconSet (QIconSet (QPixmap (playlist_xpm))); + m_buttons[button_back]->setIconSet (QIconSet (QPixmap (back_xpm))); + m_buttons[button_play]->setIconSet (QIconSet (QPixmap (play_xpm))); + m_buttons[button_forward]->setIconSet (QIconSet (QPixmap (forward_xpm))); + m_buttons[button_stop]->setIconSet (QIconSet (QPixmap (stop_xpm))); + m_buttons[button_pause]->setIconSet (QIconSet (QPixmap (pause_xpm))); + m_buttons[button_record]->setIconSet (QIconSet (QPixmap (record_xpm))); + m_buttons[button_broadcast]->setIconSet (QIconSet (QPixmap (broadcast_xpm))); + m_buttons[button_language]->setIconSet (QIconSet (QPixmap (language_xpm))); + m_buttons[button_red]->setIconSet (QIconSet (QPixmap (red_xpm))); + m_buttons[button_green]->setIconSet (QIconSet (QPixmap (green_xpm))); + m_buttons[button_yellow]->setIconSet (QIconSet (QPixmap (yellow_xpm))); + m_buttons[button_blue]->setIconSet (QIconSet (QPixmap (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]->hasMouse() && + !m_popupMenu->isVisible ()) + showPopupMenu (); + } else if (m_buttons [button_language]->hasMouse() && + !m_languageMenu->isVisible ()) { + showLanguageMenu (); + } + } else if (e->timerId () == m_popdown_timer) { + m_popdown_timer = 0; + if (m_popupMenu->isVisible () && + !m_popupMenu->hasMouse () && + !m_playerMenu->hasMouse () && + !m_zoomMenu->hasMouse () && + !m_colorMenu->hasMouse () && + !m_bookmarkMenu->hasMouse ()) { + if (!(m_bookmarkMenu->isVisible () && + static_cast <QWidget *> (m_bookmarkMenu) != QWidget::keyboardGrabber ())) { + // not if user entered the bookmark sub menu or if I forgot one + m_popupMenu->hide (); + if (m_buttons [button_config]->isOn ()) + m_buttons [button_config]->toggle (); + } + } else if (m_languageMenu->isVisible () && + !m_languageMenu->hasMouse () && + !m_audioMenu->hasMouse () && + !m_subtitleMenu->hasMouse ()) { + m_languageMenu->hide (); + if (m_buttons [button_language]->isOn ()) + m_buttons [button_language]->toggle (); + } + } + 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]->isOn ()) // 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 () { + m_view->updateVolume (); + m_popupMenu->exec (m_buttons [button_config]->mapToGlobal (QPoint (0, maximumSize ().height ()))); +} + +KDE_NO_EXPORT void ControlPanel::showLanguageMenu () { + m_languageMenu->exec (m_buttons [button_language]->mapToGlobal (QPoint (0, maximumSize ().height ()))); +} + +void ControlPanel::showPositionSlider (bool show) { + if (!m_auto_controls || show == m_posSlider->isShown ()) + 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); + if (show) { + m_posSlider->show (); + m_buttonbox->setMargin (4); + m_buttonbox->setSpacing (4); + setEraseColor (m_view->topLevelWidget ()->paletteBackgroundColor ()); + } else { + m_posSlider->hide (); + m_buttonbox->setMargin (1); + m_buttonbox->setSpacing (1); + setEraseColor (QColor (0, 0, 0)); + } + for (int i = 0; i < (int) button_last; i++) { + m_buttons[i]->setMinimumSize (15, h-1); + m_buttons[i]->setMaximumSize (750, h); + } + setMaximumSize (2500, h + (show ? 8 : 2 )); +} + +KDE_NO_EXPORT int ControlPanel::preferedHeight () { + return 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::setPlaying (bool play) { + if (play != m_buttons[button_play]->isOn ()) + 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]->isOn ()) + 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->setMaxValue (m_progress_length); + m_progress_mode = progress_playing; + } + if (pos < len && len > 0 && len != m_posSlider->maxValue ()) + m_posSlider->setMaxValue (m_progress_length); + else if (m_progress_length <= 0 && pos > 7 * m_posSlider->maxValue ()/8) + m_posSlider->setMaxValue (m_posSlider->maxValue() * 2); + else if (m_posSlider->maxValue() < pos) + m_posSlider->setMaxValue (int (1.4 * m_posSlider->maxValue())); + 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); + m_posSlider->setEnabled (false); + if (m_progress_mode != progress_loading) { + m_posSlider->setMaxValue (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 (!m_popupMenu->isVisible ()) { + m_button_monitored = button_config; + m_popup_clicked = false; + m_popup_timer = startTimer (400); + } + } else if (!m_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); + m_audioMenu->clear (); + for (int i = 0; i < sz; i++) + m_audioMenu->insertItem (alang [i], i); + sz = (int) slang.size (); + showbutton |= (sz > 0); + m_subtitleMenu->clear (); + for (int i = 0; i < sz; i++) + m_subtitleMenu->insertItem (slang [i], i); + if (showbutton) + m_buttons [button_language]->show (); + else + m_buttons [button_language]->hide (); +} + +KDE_NO_EXPORT void ControlPanel::selectSubtitle (int id) { + if (m_subtitleMenu->isItemChecked (id)) + return; + int size = m_subtitleMenu->count (); + for (int i = 0; i < size; i++) + if (m_subtitleMenu->isItemChecked (i)) { + m_subtitleMenu->setItemChecked (i, false); + break; + } + m_subtitleMenu->setItemChecked (id, true); +} + +KDE_NO_EXPORT void ControlPanel::selectAudioLanguage (int id) { + kdDebug () << "ControlPanel::selectAudioLanguage " << id << endl; + if (m_audioMenu->isItemChecked (id)) + return; + int sz = m_audioMenu->count (); + for (int i = 0; i < sz; i++) + if (m_audioMenu->isItemChecked (i)) { + m_audioMenu->setItemChecked (i, false); + break; + } + m_audioMenu->setItemChecked (id, true); +} + +//----------------------------------------------------------------------------- + +#include "kmplayercontrolpanel.moc" diff --git a/src/kmplayercontrolpanel.h b/src/kmplayercontrolpanel.h new file mode 100644 index 0000000..69f93e7 --- /dev/null +++ b/src/kmplayercontrolpanel.h @@ -0,0 +1,181 @@ +/** + * Copyright (C) 2005 by Koos Vriezen <koos ! vriezen ? gmail ! com> + * + * 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. + **/ + +#ifndef KMPLAYER_CONTROLPANEL_H +#define KMPLAYER_CONTROLPANEL_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qwidget.h> +#include <qpushbutton.h> + +#include <kpopupmenu.h> + +class QSlider; +//class QPushButton; +class QBoxLayout; +class QStringList; +class KPopupMenu; + +namespace KMPlayer { + +class View; + +/* + * A button from the controlpanel + */ +class KMPLAYER_NO_EXPORT KMPlayerMenuButton : public QPushButton { + Q_OBJECT +public: + KMPlayerMenuButton (QWidget *, QBoxLayout *, const char **, int = 0); + KDE_NO_CDTOR_EXPORT ~KMPlayerMenuButton () {} +signals: + void mouseEntered (); +protected: + void enterEvent (QEvent *); +}; + +/* + * The pop down menu from the controlpanel + */ +class KMPLAYER_EXPORT KMPlayerPopupMenu : public KPopupMenu { + Q_OBJECT +public: + KMPlayerPopupMenu (QWidget *); + KDE_NO_CDTOR_EXPORT ~KMPlayerPopupMenu () {} +signals: + void mouseLeft (); +protected: + void leaveEvent (QEvent *); +}; + +/* + * The volume bar from the controlpanel + */ +class KMPLAYER_EXPORT VolumeBar : public QWidget { + Q_OBJECT +public: + VolumeBar (QWidget * parent, View * view); + ~VolumeBar (); + KDE_NO_EXPORT int value () const { return m_value; } + void setValue (int v); +signals: + void volumeChanged (int); // 0 - 100 +protected: + void wheelEvent (QWheelEvent * e); + void paintEvent (QPaintEvent *); + void mousePressEvent (QMouseEvent * e); + void mouseMoveEvent (QMouseEvent * e); +private: + View * m_view; + int m_value; +}; + +/* + * The controlpanel GUI + */ +class KMPLAYER_EXPORT ControlPanel : public QWidget { + Q_OBJECT +public: + enum MenuID { + menu_config = 0, menu_player, menu_fullscreen, menu_volume, + menu_bookmark, menu_zoom, menu_zoom50, menu_zoom100, menu_zoom150, + menu_view, menu_video, menu_playlist + }; + enum Button { + button_config = 0, button_playlist, + button_back, button_play, button_forward, + button_stop, button_pause, button_record, + button_broadcast, button_language, + button_red, button_green, button_yellow, button_blue, + button_last + }; + ControlPanel (QWidget * parent, View * view); + KDE_NO_CDTOR_EXPORT ~ControlPanel () {} + void showPositionSlider (bool show); + void enableSeekButtons (bool enable); + void enableRecordButtons (bool enable); + void setPlaying (bool play); + void setRecording (bool record); + void setAutoControls (bool b); + void setPalette (const QPalette &); + int preferedHeight (); + KDE_NO_EXPORT bool autoControls () const { return m_auto_controls; } + KDE_NO_EXPORT QSlider * positionSlider () const { return m_posSlider; } + KDE_NO_EXPORT QSlider * contrastSlider () const { return m_contrastSlider; } + KDE_NO_EXPORT QSlider * brightnessSlider () const { return m_brightnessSlider; } + KDE_NO_EXPORT QSlider * hueSlider () const { return m_hueSlider; } + KDE_NO_EXPORT QSlider * saturationSlider () const { return m_saturationSlider; } + QPushButton * button (Button b) const { return m_buttons [(int) b]; } + KDE_NO_EXPORT QPushButton * broadcastButton () const { return m_buttons[button_broadcast]; } + KDE_NO_EXPORT VolumeBar * volumeBar () const { return m_volume; } + KDE_NO_EXPORT KMPlayerPopupMenu * popupMenu () const { return m_popupMenu; } + KDE_NO_EXPORT KPopupMenu * bookmarkMenu () const { return m_bookmarkMenu; } + KDE_NO_EXPORT QPopupMenu * zoomMenu () const { return m_zoomMenu; } + KDE_NO_EXPORT QPopupMenu * playerMenu () const { return m_playerMenu; } + KDE_NO_EXPORT QPopupMenu * colorMenu () const { return m_colorMenu; } + KDE_NO_EXPORT QPopupMenu * audioMenu () const { return m_audioMenu; } + KDE_NO_EXPORT QPopupMenu * subtitleMenu () const { return m_subtitleMenu; } + KDE_NO_EXPORT View * view () const { return m_view; } +public slots: + void setLanguages (const QStringList & al, const QStringList & sl); + void selectSubtitle (int id); + void selectAudioLanguage (int id); + void showPopupMenu (); + void showLanguageMenu (); + void setPlayingProgress (int position, int length); + void setLoadingProgress (int pos); +protected: + void timerEvent (QTimerEvent * e); + void setupPositionSlider (bool show); +private slots: + void buttonMouseEntered (); + void buttonClicked (); + void menuMouseLeft (); +private: + enum { progress_loading, progress_playing } m_progress_mode; + int m_progress_length; + int m_popup_timer; + int m_popdown_timer; + int m_button_monitored; + View * m_view; + QBoxLayout * m_buttonbox; + QSlider * m_posSlider; + QSlider * m_contrastSlider; + QSlider * m_brightnessSlider; + QSlider * m_hueSlider; + QSlider * m_saturationSlider; + QPushButton * m_buttons [button_last]; + VolumeBar * m_volume; + KMPlayerPopupMenu * m_popupMenu; + KMPlayerPopupMenu * m_bookmarkMenu; + KMPlayerPopupMenu * m_zoomMenu; + KMPlayerPopupMenu * m_playerMenu; + KMPlayerPopupMenu * m_colorMenu; + KMPlayerPopupMenu * m_languageMenu; + KMPlayerPopupMenu * m_audioMenu; + KMPlayerPopupMenu * m_subtitleMenu; + bool m_auto_controls; // depending on source caps + bool m_popup_clicked; +}; + +} + +#endif // KMPLAYER_CONTROLPANEL_H diff --git a/src/kmplayerpartbase.cpp b/src/kmplayerpartbase.cpp new file mode 100644 index 0000000..10a9f87 --- /dev/null +++ b/src/kmplayerpartbase.cpp @@ -0,0 +1,2047 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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.h> + +#include <math.h> + +#include <qapplication.h> +#include <qcstring.h> +#include <qcursor.h> +#include <qtimer.h> +#include <qpair.h> +#include <qpushbutton.h> +#include <qpopupmenu.h> +#include <qslider.h> +#include <qfile.h> +#include <qregexp.h> +#include <qtextstream.h> + +#include <kmessagebox.h> +#include <kaboutdata.h> +#include <kdebug.h> +#include <kbookmarkmenu.h> +#include <kbookmarkmanager.h> +#include <kconfig.h> +#include <ksimpleconfig.h> +#include <kaction.h> +#include <kprocess.h> +#include <kstandarddirs.h> +#include <kmimetype.h> +#include <kprotocolinfo.h> +#include <kapplication.h> +#include <kstaticdeleter.h> +#include <kio/job.h> +#include <kio/jobclasses.h> + +#include "kmplayerpartbase.h" +#include "kmplayerview.h" +#include "playlistview.h" +#include "viewarea.h" +#include "kmplayercontrolpanel.h" +#include "kmplayerconfig.h" +#include "kmplayerprocess.h" +#include "kmplayer_smil.h" + +namespace KMPlayer { + +class KMPLAYER_NO_EXPORT BookmarkOwner : public KBookmarkOwner { +public: + BookmarkOwner (PartBase *); + KDE_NO_CDTOR_EXPORT virtual ~BookmarkOwner () {} + void openBookmarkURL(const QString& _url); + QString currentTitle() const; + QString currentURL() const; +private: + PartBase * m_player; +}; + +class KMPLAYER_NO_EXPORT BookmarkManager : public KBookmarkManager { +public: + BookmarkManager (const QString &); +}; + +} // namespace + +using namespace KMPlayer; + +KDE_NO_CDTOR_EXPORT BookmarkOwner::BookmarkOwner (PartBase * player) + : m_player (player) {} + +KDE_NO_EXPORT void BookmarkOwner::openBookmarkURL (const QString & url) { + m_player->openURL (KURL (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 (); +} + +inline BookmarkManager::BookmarkManager(const QString & bmfile) + : KBookmarkManager (bmfile, false) { +} + +//----------------------------------------------------------------------------- + +PartBase::PartBase (QWidget * wparent, const char *wname, + QObject * parent, const char *name, KConfig * config) + : KMediaPlayer::Player (wparent, wname ? wname : "kde_kmplayer_view", parent, name ? name : "kde_kmplayer_part"), + m_config (config), + m_view (new View (wparent, wname ? wname : "kde_kmplayer_view")), + m_settings (new Settings (this, config)), + m_recorder (0L), + m_source (0L), + m_bookmark_menu (0L), + m_record_timer (0), + m_update_tree_timer (0), + m_noresize (false), + m_auto_controls (true), + m_bPosSliderPressed (false), + m_in_update_tree (false) +{ + MPlayer *mplayer = new MPlayer (this, m_settings); + m_players ["mplayer"] = mplayer; + m_process = mplayer; + Xine * xine = new Xine (this, m_settings); + m_players ["xine"] = xine; + m_players ["gstreamer"] = new GStreamer (this, m_settings); + m_recorders ["mencoder"] = new MEncoder (this, m_settings); + m_recorders ["mplayerdumpstream"] = new MPlayerDumpstream(this, m_settings); + m_recorders ["ffmpeg"] = new FFMpeg (this, m_settings); + m_recorders ["xine"] = xine; + m_sources ["urlsource"] = new URLSource (this); + + QString bmfile = locate ("data", "kmplayer/bookmarks.xml"); + QString localbmfile = locateLocal ("data", "kmplayer/bookmarks.xml"); + if (localbmfile != bmfile) { + kdDebug () << "cp " << bmfile << " " << localbmfile << endl; + KProcess p; + p << "/bin/cp" << QFile::encodeName (bmfile) << QFile::encodeName (localbmfile); + p.start (KProcess::Block); + } + m_bookmark_manager = new BookmarkManager (localbmfile); + 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 (m_bookmark_manager, t, KURL (url)); + m_bookmark_manager->emitChanged (b); +} + +void PartBase::init (KActionCollection * action_collection) { + KParts::Part::setWidget (m_view); + m_view->init (action_collection); +#ifdef HAVE_NSPR + m_players ["npp"] = new NpPlayer (this, m_settings, m_service); +#endif + connect(m_settings, SIGNAL(configChanged()), this, SLOT(settingsChanged())); + m_settings->readConfig (); + m_settings->applyColorSetting (false); + m_bookmark_menu = new KBookmarkMenu (m_bookmark_manager, m_bookmark_owner, m_view->controlPanel ()->bookmarkMenu (), action_collection, true, true); + connect (m_view, SIGNAL (urlDropped (const KURL::List &)), this, SLOT (openURL (const KURL::List &))); + connectPlaylist (m_view->playList ()); + connectInfoPanel (m_view->infoPanel ()); + new KAction (i18n ("Edit playlist &item"), 0, 0, m_view->playList (), SLOT (editCurrent ()), action_collection, "edit_playlist_item"); +} + +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 (activated (int)), this, SLOT (audioSelected (int))); + connect (panel->subtitleMenu (), SIGNAL (activated (int)), this, SLOT (subtitleSelected (int))); + connect (this, SIGNAL (audioIsSelected (int)), panel, SLOT (selectAudioLanguage (int))); + connect (this, SIGNAL (subtitleIsSelected (int)), panel, SLOT (selectSubtitle (int))); + panel->popupMenu()->connectItem (ControlPanel::menu_fullscreen, this, SLOT (fullScreen ())); + panel->popupMenu ()->connectItem (ControlPanel::menu_config, + this, SLOT (showConfigDialog ())); + panel->popupMenu ()->connectItem (ControlPanel::menu_video, + m_view, SLOT(toggleVideoConsoleWindow())); + panel->popupMenu ()->connectItem (ControlPanel::menu_playlist, + 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::connectPlaylist (PlayListView * playlist) { + connect (playlist, SIGNAL (addBookMark (const QString &, const QString &)), + this, SLOT (addBookMark (const QString &, const QString &))); + connect (playlist, SIGNAL (executed (QListViewItem *)), + this, SLOT (playListItemExecuted (QListViewItem *))); + connect (playlist, SIGNAL (clicked (QListViewItem *)), + this, SLOT (playListItemClicked (QListViewItem *))); + connect (this, SIGNAL (treeChanged (int, NodePtr, NodePtr, bool, bool)), + playlist, SLOT (updateTree (int, NodePtr, NodePtr, bool, bool))); + connect (this, SIGNAL (treeUpdated ()), + playlist, SLOT (triggerUpdate ())); +} + +void PartBase::connectInfoPanel (InfoWindow * infopanel) { + connect (this, SIGNAL (infoUpdated (const QString &)), + infopanel->view (), SLOT (setInfoMessage (const QString &))); +} + +PartBase::~PartBase () { + kdDebug() << "PartBase::~PartBase" << endl; + m_view = (View*) 0; + stop (); + if (m_source) + m_source->deactivate (); + delete m_settings; + delete m_bookmark_menu; + delete m_bookmark_manager; + delete m_bookmark_owner; +} + +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; + +bool PartBase::setProcess (Mrl *mrl) { + // determine backend, start with temp_backends + QString p = temp_backends [m_source->name()]; + bool remember_backend = p.isEmpty (); + bool changed = false; + if (p.isEmpty ()) { + // next try to find mimetype match from kmplayerrc + if (!mrl->mimetype.isEmpty ()) { + m_config->setGroup (mrl->mimetype); + p = m_config->readEntry ("player", "" ); + remember_backend = !(!p.isEmpty () && + m_players.contains (p) && + m_players [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 + m_config->setGroup (strGeneralGroup); + p = m_config->readEntry (m_source->name (), ""); + } + if (p.isEmpty () || + !m_players.contains (p) || + !m_players [p]->supports (m_source->name ())) { + // finally find first supported player + p.truncate (0); + if (!m_process || !m_process->supports (m_source->name ())) { + ProcessMap::const_iterator i, e = m_players.end(); + for (i = m_players.begin(); i != e; ++i) + if (i.data ()->supports (m_source->name ())) { + p = QString (i.data ()->name ()); + break; + } + } else + p = QString (m_process->name ()); + } + if (!p.isEmpty ()) { + if (!m_process || p != m_process->name ()) { + setProcess (p.ascii ()); + updatePlayerMenu (m_view->controlPanel ()); + changed = true; + } + if (remember_backend) + m_settings->backends [m_source->name()] = m_process->name (); + else + temp_backends.remove (m_source->name()); + } + return changed; +} + +void PartBase::setProcess (const char * name) { + Process * process = name ? m_players [name] : 0L; + if (m_process == process) + return; + if (!m_source) + m_source = m_sources ["urlsource"]; + Process * old_process = m_process; + m_process = process; + if (old_process && old_process->state () > Process::NotRunning) + old_process->quit (); + if (!m_process) + return; + m_process->setSource (m_source); + if (m_process->playing ()) { + m_view->controlPanel ()->setPlaying (true); + m_view->controlPanel ()->showPositionSlider (!!m_source->length ()); + m_view->controlPanel ()->enableSeekButtons (m_source->isSeekable ()); + } + emit processChanged (name); +} + +void PartBase::setRecorder (const char * name) { + Process * recorder = name ? m_recorders [name] : 0L; + if (m_recorder == recorder) + return; + if (m_recorder) + m_recorder->quit (); + m_recorder = recorder; +} + +KDE_NO_EXPORT void PartBase::slotPlayerMenu (int id) { + bool playing = m_process->playing (); + const char * srcname = m_source->name (); + QPopupMenu * menu = m_view->controlPanel ()->playerMenu (); + ProcessMap::const_iterator pi = m_players.begin(), e = m_players.end(); + unsigned i = 0; + for (; pi != e && i < menu->count(); ++pi) { + Process * proc = pi.data (); + if (!proc->supports (srcname)) + continue; + int menuid = menu->idAt (i); + menu->setItemChecked (menuid, menuid == id); + if (menuid == id) { + if (proc->name () != QString ("npp")) + m_settings->backends [srcname] = proc->name (); + temp_backends [srcname] = proc->name (); + if (playing && strcmp (m_process->name (), proc->name ())) + m_process->quit (); + setProcess (proc->name ()); + } + ++i; + } + if (playing) + setSource (m_source); // re-activate +} + +void PartBase::updatePlayerMenu (ControlPanel * panel) { + if (!m_view || !m_process) + return; + QPopupMenu * menu = panel->playerMenu (); + menu->clear (); + if (!m_source) + return; + const ProcessMap::const_iterator e = m_players.end(); + int id = 0; // if multiple parts, id's should be the same for all menu's + for (ProcessMap::const_iterator i = m_players.begin(); i != e; ++i) { + Process * p = i.data (); + if (p->supports (m_source->name ())) { + menu->insertItem (p->menuName (), this, SLOT (slotPlayerMenu (int)), 0, id++); + if (i.data() == m_process) + menu->setItemChecked (id-1, 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 (playingStarted ())); + disconnect (old_source, SIGNAL (stopPlaying ()), + this, SLOT (playingStopped ())); + } + if (source) { + connect (source, SIGNAL (endOfPlayItems ()), this, SLOT (stop ())); + connect (source, SIGNAL (dimensionsChanged ()), + this, SLOT (sourceHasChangedAspects ())); + connect (source, SIGNAL (startPlaying()), this, SLOT(playingStarted())); + connect (source, SIGNAL (stopPlaying ()), this, SLOT(playingStopped())); + } +} + +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 (m_source, SIGNAL (startRecording ()), + this, SLOT (recordingStarted ())); + 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); + m_process->setSource (m_source); + connect (m_source, SIGNAL(startRecording()), this,SLOT(recordingStarted())); + 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 && m_view->viewer ()) { + updatePlayerMenu (m_view->controlPanel ()); + m_view->viewer ()->setAspect (0.0); + } + if (m_source) QTimer::singleShot (0, m_source, SLOT (activate ())); + 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; +} + +unsigned long PartBase::length () const { + return m_source ? m_source->length () : 0; +} + +bool PartBase::openURL (const KURL & url) { + kdDebug () << "PartBase::openURL " << url.url() << url.isValid () << endl; + 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"])); + src->setSubURL (KURL ()); + src->setURL (url); + setSource (src); + return true; +} + +bool PartBase::openURL (const KURL::List & urls) { + if (urls.size () == 1) { + openURL (urls[0]); + } else { + openURL (KURL ()); + NodePtr d = m_source->document (); + if (d) + for (unsigned int i = 0; i < urls.size (); i++) + d->appendChild (new GenericURL (d, KURL::decode_string (urls [i].url ()))); + } + return true; +} + +bool PartBase::closeURL () { + stop (); + if (m_view) { + m_view->viewer ()->setAspect (0.0); + m_view->reset (); + } + return true; +} + +bool PartBase::openFile () { + return false; +} + +void PartBase::keepMovieAspect (bool b) { + if (m_view) { + m_view->setKeepSizeRatio (b); + if (m_source) + m_view->viewer ()->setAspect (b ? m_source->aspect () : 0.0); + } +} + +void PartBase::recordingStarted () { + if (m_settings->replayoption == Settings::ReplayAfter) + m_record_timer = startTimer (1000 * m_settings->replaytime); +} + +void PartBase::recordingStopped () { + killTimer (m_record_timer); + m_record_timer = 0; + Recorder * rec = dynamic_cast <Recorder*> (m_recorder); + if (rec) { + if (m_settings->replayoption == Settings::ReplayFinished || + (m_settings->replayoption == Settings::ReplayAfter && !playing ())) + openURL (rec->recordURL ()); + rec->setURL (KURL ()); + } + setRecorder ("mencoder"); //FIXME see PartBase::record() checking playing() +} + +void PartBase::timerEvent (QTimerEvent * e) { + if (e->timerId () == m_record_timer) { + kdDebug () << "record timer event" << (m_recorder->playing () && !playing ()) << endl; + m_record_timer = 0; + if (m_recorder->playing () && !playing ()) { + Recorder * rec = dynamic_cast <Recorder*> (m_recorder); + if (rec) { + openURL (rec->recordURL ()); + rec->setURL (KURL ()); + } + } + } else if (e->timerId () == m_update_tree_timer) { + m_update_tree_timer = 0; + updateTree (m_update_tree_full, true); + } + killTimer (e->timerId ()); +} + +void PartBase::playingStarted () { + //m_view->viewer ()->setAspect (m_source->aspect ()); + if (m_view) { + m_view->controlPanel ()->setPlaying (true); + m_view->controlPanel ()->showPositionSlider (!!m_source->length ()); + m_view->controlPanel ()->enableSeekButtons (m_source->isSeekable ()); + if (m_settings->autoadjustvolume && m_process) + m_process->volume(m_view->controlPanel()->volumeBar()->value(),true); + } + emit loading (100); +} + +void PartBase::playingStopped () { + kdDebug () << "playingStopped " << this << endl; + if (m_view) { + m_view->controlPanel ()->setPlaying (false); + m_view->reset (); + } + m_bPosSliderPressed = false; +} + +KDE_NO_EXPORT void PartBase::setPosition (int position, int length) { + if (m_view && !m_bPosSliderPressed) + emit positioned (position, length); +} + +void PartBase::setLoaded (int percentage) { + emit loading (percentage); +} + +unsigned long PartBase::position () const { + return m_source ? 100 * m_source->position () : 0; +} + +void PartBase::pause () { + NodePtr doc = m_source ? m_source->document () : 0L; + if (doc) { + if (doc->state == Node::state_deferred) + doc->undefer (); + else + doc->defer (); + } +} + +void PartBase::back () { + m_source->backward (); +} + +void PartBase::forward () { + m_source->forward (); +} + +KDE_NO_EXPORT void PartBase::playListItemClicked (QListViewItem * item) { + if (!item) + return; + PlayListItem * vi = static_cast <PlayListItem *> (item); + RootPlayListItem * ri = vi->playListView ()->rootItem (item); + if (ri == item && vi->node) { + QString src = ri->source; + //kdDebug() << "playListItemClicked " << src << " " << vi->node->nodeName() << endl; + Source * source = src.isEmpty() ? m_source : m_sources[src.ascii()]; + if (vi->node->isPlayable ()) { + source->jump (vi->node); //may become !isPlayable by lazy loading + if (!vi->node->isPlayable ()) + emit treeChanged (ri->id, vi->node, 0, false, true); + } else if (vi->firstChild ()) + vi->listView ()->setOpen (vi, !vi->isOpen ()); + } else if (!vi->node && !vi->m_attr) + updateTree (); // items already deleted +} + +KDE_NO_EXPORT void PartBase::playListItemExecuted (QListViewItem * item) { + if (m_in_update_tree) return; + if (m_view->editMode ()) return; + PlayListItem * vi = static_cast <PlayListItem *> (item); + RootPlayListItem * ri = vi->playListView ()->rootItem (item); + if (ri == item) + return; // both null or handled by playListItemClicked + if (vi->node) { + QString src = ri->source; + //kdDebug() << "playListItemExecuted " << src << " " << vi->node->nodeName() << endl; + Source * source = src.isEmpty() ? m_source : m_sources[src.ascii()]; + if (vi->node->isPlayable ()) { + source->jump (vi->node); //may become !isPlayable by lazy loading + if (!vi->node->isPlayable ()) + emit treeChanged (ri->id, vi->node, 0, false, true); + } else if (vi->firstChild ()) + vi->listView ()->setOpen (vi, !vi->isOpen ()); + } else if (vi->m_attr) { + if (vi->m_attr->name () == StringPool::attr_src || + vi->m_attr->name () == StringPool::attr_href || + vi->m_attr->name () == StringPool::attr_url || + vi->m_attr->name () == StringPool::attr_value || + vi->m_attr->name () == "data") { + QString src (vi->m_attr->value ()); + if (!src.isEmpty ()) { + PlayListItem * pi = static_cast <PlayListItem*>(item->parent()); + if (pi) { + for (NodePtr e = pi->node; 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); + } else + emit treeUpdated (); + 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 (int id) { + emit audioIsSelected (id); +} + +KDE_NO_EXPORT void PartBase::subtitleSelected (int id) { + emit subtitleIsSelected (id); +} + +void PartBase::record () { + if (m_view) m_view->setCursor (QCursor (Qt::WaitCursor)); + if (m_recorder->playing ()) { + m_recorder->stop (); + } else { + m_settings->show ("RecordPage"); + m_view->controlPanel ()->setRecording (false); + } + if (m_view) m_view->setCursor (QCursor (Qt::ArrowCursor)); +} + +void PartBase::play () { + if (!m_process || !m_view) return; + QPushButton * pb = ::qt_cast <QPushButton *> (sender ()); + if (pb && !pb->isOn ()) { + stop (); + return; + } + if (m_update_tree_timer) { + killTimer (m_update_tree_timer); + m_update_tree_timer = 0; + } + if (m_process->state () == Process::NotRunning) { + PlayListItem * lvi = m_view->playList ()->currentPlayListItem (); + if (lvi) { // make sure it's in the first tree + QListViewItem * pitem = lvi; + while (pitem->parent()) + pitem = pitem->parent(); + if (pitem != m_view->playList ()->firstChild ()) + lvi = 0L; + } + if (!lvi) + lvi = static_cast<PlayListItem*>(m_view->playList()->firstChild()); + if (lvi) + for (NodePtr n = lvi->node; n; n = n->parentNode ()) { + if (n->isPlayable ()) { + m_source->setCurrent (n); + break; + } + } + m_process->ready (m_view->viewer ()); + } else if (m_process->state () == Process::Ready) { + m_source->playCurrent (); + } else + m_process->play (m_source, m_source->current ()); +} + +bool PartBase::playing () const { + return m_process && m_process->state () > Process::Ready; +} + +void PartBase::stop () { + QPushButton * b = m_view ? m_view->controlPanel ()->button (ControlPanel::button_stop) : 0L; + if (b) { + if (!b->isOn ()) + b->toggle (); + m_view->setCursor (QCursor (Qt::WaitCursor)); + } + if (m_process) + m_process->quit (); + if (m_source) + m_source->reset (); + if (m_view) { + m_view->setCursor (QCursor (Qt::ArrowCursor)); + if (b->isOn ()) + b->toggle (); + m_view->controlPanel ()->setPlaying (false); + setLoaded (100); + } +} + +void PartBase::seek (unsigned long msec) { + if (m_process) + m_process->seek (msec/100, true); +} + +void PartBase::adjustVolume (int incdec) { + m_process->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 <const QSlider *> (sender ()); +#else + const QSlider * posSlider = ::qt_cast<const QSlider *> (sender ()); +#endif + if (posSlider) + m_process->seek (posSlider->value(), true); +} + +KDE_NO_EXPORT void PartBase::volumeChanged (int val) { + if (m_process) { + m_settings->volume = val; + m_process->volume (val, true); + } +} + +KDE_NO_EXPORT void PartBase::contrastValueChanged (int val) { + m_settings->contrast = val; + m_process->contrast (val, true); +} + +KDE_NO_EXPORT void PartBase::brightnessValueChanged (int val) { + m_settings->brightness = val; + m_process->brightness (val, true); +} + +KDE_NO_EXPORT void PartBase::hueValueChanged (int val) { + m_settings->hue = val; + m_process->hue (val, true); +} + +KDE_NO_EXPORT void PartBase::saturationValueChanged (int val) { + m_settings->saturation = val; + m_process->saturation (val, true); +} + +KDE_NO_EXPORT void PartBase::sourceHasChangedAspects () { + if (m_view && m_source) { + //kdDebug () << "sourceHasChangedAspects " << m_source->aspect () << endl; + m_view->viewer ()->setAspect (m_source->aspect ()); + m_view->updateLayout (); + } + emit sourceDimensionChanged (); +} + +KDE_NO_EXPORT void PartBase::positionValueChanged (int pos) { + QSlider * slider = ::qt_cast <QSlider *> (sender ()); + if (slider && slider->isEnabled ()) + m_process->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; +} + +//----------------------------------------------------------------------------- + +Source::Source (const QString & name, PartBase * player, const char * n) + : QObject (player, n), + m_name (name), m_player (player), m_identified (false), m_auto_play (true), + 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; + Q_ASSERT (m_current.ptr () == 0L); +} + +void Source::init () { + //setDimensions (320, 240); + m_width = 0; + m_height = 0; + m_aspect = 0.0; + m_length = 0; + m_position = 0; + setLength (m_document, 0); + m_recordcmd.truncate (0); +} + +KDE_NO_EXPORT void Source::setLanguages (const QStringList & alang, const QStringList & slang) { + m_player->setLanguages (alang, slang); +} + +void Source::setDimensions (NodePtr node, int w, int h) { + Mrl * mrl = node ? node->mrl () : 0L; + if (mrl && mrl->view_mode == Mrl::WindowMode) { + mrl->width = w; + mrl->height = h; + float a = h > 0 ? 1.0 * w / h : 0.0; + mrl->aspect = a; + if (m_player->view ()) { + static_cast <View *> (m_player->view())->viewer()->setAspect(a); + static_cast <View *> (m_player->view ())->updateLayout (); + } + } else if (m_aspect < 0.001 || m_width != w || m_height != h) { + bool ev = (w > 0 && h > 0) || + (h == 0 && m_height > 0) || + (w == 0 && m_width > 0); + m_width = w; + m_height = h; + if (m_aspect < 0.001) + setAspect (node, h > 0 ? 1.0 * w / h : 0.0); + //kdDebug () << "setDimensions " << w << "x" << h << " a:" << m_aspect << endl; + if (ev) + emit dimensionsChanged (); + } +} + +void Source::setAspect (NodePtr node, float a) { + //kdDebug () << "setAspect " << a << endl; + Mrl * mrl = node ? node->mrl () : 0L; + bool changed = false; + if (mrl) { + 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) + 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) { + kdDebug() << off << "[null]" << endl; + return; + } + kdDebug() << off << root->nodeName() << " " << (Element*)root << (root->isPlayable() ? root->mrl ()->src : QString ("-")) << endl; + off += QString (" "); + for (NodePtr e = root->firstChild(); e; e = e->nextSibling()) + printTree(e, off); +}*/ + +void Source::setURL (const KURL & url) { + m_url = url; + m_back_request = 0L; + if (m_document && !m_document->hasChildNodes () && + (m_document->mrl()->src.isEmpty () || + m_document->mrl()->src == url.url ())) + // special case, mime is set first by plugin FIXME v + m_document->mrl()->src = url.url (); + else { + if (m_document) + m_document->document ()->dispose (); + m_document = new Document (url.url (), this); + } + if (m_player->process () && m_player->source () == this) + m_player->updateTree (); + //kdDebug() << name() << " setURL " << url << endl; + m_current = m_document; +} + +void Source::setTitle (const QString & title) { + emit titleChanged (title); +} + +KDE_NO_EXPORT void Source::setAudioLang (int id) { + View * v = static_cast <View *> (m_player->view()); + if (v && m_player->process ()) + m_player->process ()->setAudioLang (id, v->controlPanel ()->audioMenu ()->text (id)); +} + +KDE_NO_EXPORT void Source::setSubtitle (int id) { + View * v = static_cast <View *> (m_player->view()); + if (v && m_player->process ()) + m_player->process ()->setSubtitle (id, v->controlPanel ()->subtitleMenu ()->text (id)); +} + +void Source::reset () { + if (m_document) { + //kdDebug() << "Source::first" << endl; + m_current = NodePtr (); + m_document->reset (); + m_player->updateTree (); + } + init (); +} + +QString Source::currentMrl () { + Mrl * mrl = m_current ? m_current->mrl () : 0L; + kdDebug() << "Source::currentMrl " << (m_current ? m_current->nodeName():"") << " src:" << (mrl ? mrl->absolutePath () : QString ()) << endl; + return mrl ? mrl->absolutePath () : QString (); +} + +void Source::playCurrent () { + QString url = currentMrl (); + m_player->changeURL (url); + m_width = m_height = 0; + m_aspect = 0.0; + if (m_player->view ()) + static_cast <View *> (m_player->view ())->playingStop ();//show controls + if (m_document && !m_document->active ()) { + if (!m_current) + m_document->activate (); + else { // ugly code duplicate w/ back_request + for (NodePtr p = m_current->parentNode(); p; p = p->parentNode()) + p->state = Element::state_activated; + m_current->activate (); + } + } else if (!m_current) { + emit endOfPlayItems (); + } else if (m_current->state == Element::state_deferred) { + // m_current->undefer (); + } else if (m_player->process ()->state () == Process::NotRunning) { + m_player->process ()->ready (static_cast <View *> (m_player->view ())->viewer ()); + } else if (m_player->process ()) { + Mrl * mrl = m_back_request ? m_back_request->mrl () : m_current->mrl (); + if (mrl->view_mode == Mrl::SingleMode) { + // don't reset the dimensions if we have any + m_width = mrl->width; + m_height = mrl->height; + m_aspect = mrl->aspect; + } + m_back_request = 0L; + m_player->process ()->play (this, mrl->linkNode ()); + } + //kdDebug () << "Source::playCurrent " << (m_current ? m_current->nodeName():" doc act:") << (m_document && !m_document->active ()) << " cur:" << (!m_current) << " cur act:" << (m_current && !m_current->active ()) << endl; + m_player->updateTree (); + emit dimensionsChanged (); +} + +static NodePtr findDepthFirst (NodePtr elm) { + if (!elm) + return NodePtr (); + NodePtr tmp = elm; + for ( ; tmp; tmp = tmp->nextSibling ()) { + if (tmp->isPlayable ()) + return tmp; + NodePtr tmp2 = findDepthFirst (tmp->firstChild ()); + if (tmp2) + return tmp2; + } + return NodePtr (); +} + +bool Source::requestPlayURL (NodePtr mrl) { + //kdDebug() << "Source::requestPlayURL " << mrl->mrl ()->src << endl; + if (m_player->process ()->state () > Process::Ready) { + if (m_player->process ()->mrl () == mrl->mrl ()->linkNode ()) + return true; + m_back_request = mrl; // still playing, schedule it + m_player->process ()->stop (); + } else { + if (mrl->mrl ()->view_mode == Mrl::SingleMode) + m_current = mrl; + else + m_back_request = mrl; + m_player->updateTree (); + QTimer::singleShot (0, this, SLOT (playCurrent ())); + } + m_player->setProcess (mrl->mrl ()); + return true; +} + +bool Source::resolveURL (NodePtr) { + return true; +} + +void Source::setTimeout (int ms) { + //kdDebug () << "Source::setTimeout " << ms << endl; + 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 ()); +} + +bool Source::setCurrent (NodePtr mrl) { + m_current = mrl; + return true; +} + +void Source::stateElementChanged (Node * elm, Node::State os, Node::State ns) { + //kdDebug() << "[01;31mSource::stateElementChanged[00m " << elm->nodeName () << " state:" << (int) elm->state << " cur isPlayable:" << (m_current && m_current->isPlayable ()) << " elm==linkNode:" << (m_current && elm == m_current->mrl ()->linkNode ()) << " p state:" << m_player->process ()->state () << endl; + if (ns == Node::state_deactivated && elm == m_document && !m_back_request) { + emit endOfPlayItems (); // played all items + } else if ((ns == Node::state_deactivated || ns == Node::state_finished) && + m_player->process ()->mrl() && + elm == m_player->process ()->mrl ()->mrl ()->linkNode ()) { + if (m_player->process ()->state () > Process::Ready) + //a SMIL movies stopped by SMIL events rather than movie just ending + m_player->process ()->stop (); + if (m_player->view ()) // move away the video widget + QTimer::singleShot (0, m_player->view (), SLOT (updateLayout ())); + } else if ((ns == Node::state_deferred || + (os == Node::state_deferred && ns > Node::state_deferred)) && + elm == m_document) { + m_player->process ()->pause (); + } else if (ns == Node::state_activated && + elm->isPlayable () && + elm->mrl ()->view_mode == Mrl::SingleMode) { + Node *p = elm->parentNode(); + if (!p || !p->mrl () || p->mrl ()->view_mode == Mrl::SingleMode) + // make sure we don't set current to nested document + m_current = elm; + } + if (elm->expose ()) { + 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); + } +} + +SurfacePtr Source::getSurface (NodePtr n) { + if (m_player->view ()) + return static_cast <View*>(m_player->view())->viewArea()->getSurface(n); + return 0L; +} + +void Source::setInfoMessage (const QString & msg) { + m_player->updateInfo (msg); +} + +void Source::bitRates (int & preferred, int & maximal) { + preferred = 1024 * m_player->settings ()->prefbitrate; + maximal= 1024 * m_player->settings ()->maxbitrate; +} + +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); + kdDebug() << "Source::insertURL " << KURL (cur_url) << " " << url << endl; + if (!url.isValid ()) + kdError () << "try to append non-valid url" << endl; + else if (KURL (cur_url) == url) + kdError () << "try to append url to itself" << endl; + else { + int depth = 0; // cache this? + for (NodePtr e = node; e->parentNode (); e = e->parentNode ()) + ++depth; + if (depth < 40) { + node->appendChild (new GenericURL (m_document, KURL::decode_string (url.url ()), title.isEmpty() ? KURL::decode_string (mrl) : title)); + m_player->updateTree (); + } else + kdError () << "insertURL exceeds depth limit" << endl; + } +} + +void Source::play () { + m_player->updateTree (); + QTimer::singleShot (0, m_player, SLOT (play ())); + //printTree (m_document); +} + +void Source::backward () { + if (m_document->hasChildNodes ()) { + m_back_request = m_current; + if (!m_back_request || m_back_request == m_document) { + m_back_request = m_document->lastChild (); + while (m_back_request->lastChild () && !m_back_request->isPlayable ()) + m_back_request = m_back_request->lastChild (); + if (m_back_request->isPlayable ()) + return; + } + while (m_back_request && m_back_request != m_document) { + if (m_back_request->previousSibling ()) { + m_back_request = m_back_request->previousSibling (); + NodePtr e = findDepthFirst (m_back_request); // lastDepth.. + if (e) { + m_back_request = e; + if (m_player->playing ()) + m_player->process ()->stop (); + else if (m_current) { + m_document->reset (); + m_current = e; + QTimer::singleShot (0, this, SLOT (playCurrent ())); + } + return; + } + } else + m_back_request = m_back_request->parentNode (); + } + m_back_request = 0L; + } else + m_player->process ()->seek (-1 * m_player->settings ()->seektime * 10, false); +} + +void Source::forward () { + if (m_document->hasChildNodes ()) { + if (m_player->playing ()) + m_player->process ()->stop (); + else if (m_current) + m_current->finish (); + } else + m_player->process ()->seek (m_player->settings()->seektime * 10, false); +} + +void Source::jump (NodePtr e) { + if (e->isPlayable ()) { + if (m_player->playing ()) { + m_back_request = e; + m_player->process ()->stop (); + } else { + if (m_current) + m_document->reset (); + m_current = e; + QTimer::singleShot (0, this, SLOT (playCurrent ())); + } + } else + m_player->updateTree (); +} + +NodePtr Source::document () { + if (!m_document) + m_document = new Document (QString (), this); + 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.length()-1); + } + return PPargs; +} + +bool Source::hasLength () { + return true; +} + +bool Source::isSeekable () { + return true; +} + +void Source::setIdentified (bool b) { + //kdDebug () << "Source::setIdentified " << m_identified << b <<endl; + m_identified = b; +} + +static const QString statemap [] = { + i18n ("Not Running"), i18n ("Ready"), i18n ("Buffering"), i18n ("Playing") +}; + +void Source::stateChange(Process *p, Process::State olds, Process::State news) { + if (!p || !p->viewer ()) return; + Recorder *rec = dynamic_cast <Recorder *> (p); + if (rec && !rec->recordURL ().isEmpty ()) { + kdDebug () << "recordState " << statemap[olds] << " -> " << statemap[news] << endl; + m_player->updateStatus (i18n ("Recorder %1 %2").arg (p->name ()).arg (statemap[news])); + p->viewer ()->view ()->controlPanel ()->setRecording (news > Process::Ready); + if (news == Process::Ready) { + if (olds > Process::Ready) { + p->quit (); + } else { + NodePtr n = current (); + if (!n) + n = document (); + p->play (this, n); + } + } else if (news > Process::Ready) { + emit startRecording (); + } else if (news == Process::NotRunning) + emit stopRecording (); + } else { + p->viewer()->view()->controlPanel()->setPlaying(news > Process::Ready); + kdDebug () << "processState " << statemap[olds] << " -> " << statemap[news] << endl; + m_player->updateStatus (i18n ("Player %1 %2").arg (p->name ()).arg (statemap[news])); + if (!p->mrl () && news > Process::Ready) { + p->stop (); // reschedule for Ready state + } else if (news == Process::Playing) { + if (p->mrl ()->state == Element::state_deferred) + p->mrl ()->undefer (); + p->viewer ()->view ()->playingStart (); + emit startPlaying (); + } else if (news == Process::NotRunning) { + if (hasLength () && position () > length ()) + setLength (m_document, position ()); + setPosition (0); + if (p == m_player->process ()) + emit stopPlaying (); + // else changed process + } else if (news == Process::Ready) { + if (olds > Process::Ready) { + NodePtr node = p->mrl (); // p->mrl is weak, needs check + Mrl * mrl = node ? node->mrl () : 0L; + if (m_back_request && m_back_request->isPlayable ()) { + if (m_back_request->mrl ()->view_mode == Mrl::SingleMode) + // jump in pl + m_current = m_back_request; + else if (mrl) + // overlapping SMIL audio/video + mrl->endOfFile (); + if (m_current->id >= SMIL::id_node_first && + m_current->id < SMIL::id_node_last) { + playCurrent (); // just play back_request + } else { + // sanitize pl having all parents of current activated + m_document->reset (); // deactivate everything + for (NodePtr p = m_current->parentNode(); p; p = p->parentNode()) + p->state = Element::state_activated; + m_current->activate (); // calls requestPlayUrl + } + m_back_request = 0L; + } else if(mrl) + { + mrl->endOfFile (); // set node to finished + } + if (m_player->view() && + (!mrl || mrl->view_mode != Mrl::WindowMode)) + static_cast<View*>(m_player->view())->viewArea()->repaint(); + } else + QTimer::singleShot (0, this, SLOT (playCurrent ())); + } else if (news == Process::Buffering) { + if (p->mrl ()->mrl ()->view_mode != Mrl::SingleMode) + p->mrl ()->defer (); // paused the SMIL + } + } +} + +QString Source::plugin (const QString &mime) const { + m_player->config ()->setGroup (mime); + return m_player->config ()->readEntry ("plugin", "" ); +} + +QString Source::prettyName () { + return i18n ("Unknown"); +} + +//----------------------------------------------------------------------------- + +URLSource::URLSource (PartBase * player, const KURL & url) + : Source (i18n ("URL"), player, "urlsource"), activated (false) { + setURL (url); + //kdDebug () << "URLSource::URLSource" << endl; +} + +URLSource::~URLSource () { + //kdDebug () << "URLSource::~URLSource" << endl; +} + +void URLSource::init () { + Source::init (); +} + +void URLSource::dimensions (int & w, int & h) { + if (!m_player->mayResize () && m_player->view ()) { + w = static_cast <View *> (m_player->view ())->viewer ()->width (); + h = static_cast <View *> (m_player->view ())->viewer ()->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 (); +} + +KDE_NO_EXPORT void URLSource::stopResolving () { + if (m_resolve_info) { + for (SharedPtr <ResolveInfo> ri = m_resolve_info; ri; ri = ri->next) + ri->job->kill (); + m_resolve_info = 0L; + m_player->updateStatus (i18n ("Disconnected")); + m_player->setLoaded (100); + } +} + +void URLSource::reset () { + stopResolving (); + Source::reset (); +} + +void URLSource::forward () { + stopResolving (); + Source::forward (); +} + +void URLSource::backward () { + stopResolving (); + Source::backward (); +} + +void URLSource::jump (NodePtr e) { + stopResolving (); + Source::jump (e); +} + +void URLSource::deactivate () { + activated = false; + reset (); + getSurface (0L); +} + +QString URLSource::prettyName () { + if (m_url.isEmpty ()) + return i18n ("URL"); + if (m_url.url ().length () > 50) { + QString newurl = m_url.protocol () + QString ("://"); + if (m_url.hasHost ()) + newurl += m_url.host (); + if (m_url.port ()) + newurl += QString (":%1").arg (m_url.port ()); + QString file = m_url.fileName (); + int len = newurl.length () + file.length (); + KURL path = KURL (m_url.directory ()); + bool modified = false; + while (path.url ().length () + 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 - %1").arg (newurl); + } + return i18n ("URL - %1").arg (m_url.prettyURL ()); +} + +static bool isPlayListMime (const QString & mime) { + QString m (mime); + int plugin_pos = m.find ("-plugin"); + if (plugin_pos > 0) + m.truncate (plugin_pos); + const char * mimestr = m.ascii (); + return mimestr && (!strcmp (mimestr, "audio/mpegurl") || + !strcmp (mimestr, "audio/x-mpegurl") || + !strncmp (mimestr, "video/x-ms", 10) || + !strncmp (mimestr, "audio/x-ms", 10) || + //!strcmp (mimestr, "video/x-ms-wmp") || + //!strcmp (mimestr, "video/x-ms-asf") || + //!strcmp (mimestr, "video/x-ms-wmv") || + //!strcmp (mimestr, "video/x-ms-wvx") || + //!strcmp (mimestr, "video/x-msvideo") || + !strcmp (mimestr, "audio/x-scpls") || + !strcmp (mimestr, "audio/x-pn-realaudio") || + !strcmp (mimestr, "audio/vnd.rn-realaudio") || + !strcmp (mimestr, "audio/m3u") || + !strcmp (mimestr, "audio/x-m3u") || + !strncmp (mimestr, "text/", 5) || + (!strncmp (mimestr, "application/", 12) && + strstr (mimestr + 12,"+xml")) || + !strncasecmp (mimestr, "application/smil", 16) || + !strncasecmp (mimestr, "application/xml", 15) || + //!strcmp (mimestr, "application/rss+xml") || + //!strcmp (mimestr, "application/atom+xml") || + !strcmp (mimestr, "application/x-mplayer2")); +} + +KDE_NO_EXPORT void URLSource::read (NodePtr root, QTextStream & textstream) { + QString line; + do { + line = textstream.readLine (); + } while (!line.isNull () && line.stripWhiteSpace ().isEmpty ()); + if (!line.isNull ()) { + NodePtr cur_elm = root; + if (cur_elm->isPlayable ()) + cur_elm = cur_elm->mrl ()->linkNode (); + if (cur_elm->mrl ()->mimetype == QString ("audio/x-scpls")) { + bool groupfound = false; + int nr = -1; + struct Entry { + QString url, title; + } * entries = 0L; + do { + line = line.stripWhiteSpace (); + if (!line.isEmpty ()) { + if (line.startsWith (QString ("[")) && line.endsWith (QString ("]"))) { + if (!groupfound && line.mid (1, line.length () - 2).stripWhiteSpace () == QString ("playlist")) + groupfound = true; + else + break; + kdDebug () << "Group found: " << line << endl; + } else if (groupfound) { + int eq_pos = line.find (QChar ('=')); + if (eq_pos > 0) { + if (line.lower ().startsWith (QString ("numberofentries"))) { + nr = line.mid (eq_pos + 1).stripWhiteSpace ().toInt (); + kdDebug () << "numberofentries : " << nr << endl; + if (nr > 0 && nr < 1024) + entries = new Entry[nr]; + else + nr = 0; + } else if (nr > 0) { + QString ll = line.lower (); + if (ll.startsWith (QString ("file"))) { + int i = line.mid (4, eq_pos-4).toInt (); + if (i > 0 && i <= nr) + entries[i-1].url = line.mid (eq_pos + 1).stripWhiteSpace (); + } else if (ll.startsWith (QString ("title"))) { + int i = line.mid (5, eq_pos-5).toInt (); + if (i > 0 && i <= nr) + entries[i-1].title = line.mid (eq_pos + 1).stripWhiteSpace (); + } + } + } + } + } + line = textstream.readLine (); + } while (!line.isNull ()); + for (int i = 0; i < nr; i++) + if (!entries[i].url.isEmpty ()) + cur_elm->appendChild (new GenericURL (m_document, KURL::decode_string (entries[i].url), entries[i].title)); + delete [] entries; + } else if (line.stripWhiteSpace ().startsWith (QChar ('<'))) { + readXML (cur_elm, textstream, line); + //cur_elm->normalize (); + if (m_document && m_document->firstChild ()) { + // SMIL documents have set its size of root-layout + Mrl * mrl = m_document->firstChild ()->mrl (); + if (mrl) + Source::setDimensions (m_document->firstChild (), mrl->width, mrl->height); + } + } else if (line.lower () != QString ("[reference]")) do { + QString mrl = line.stripWhiteSpace (); + if (line == QString ("--stop--")) + break; + if (mrl.lower ().startsWith (QString ("asf "))) + mrl = mrl.mid (4).stripWhiteSpace (); + if (!mrl.isEmpty () && !mrl.startsWith (QChar ('#'))) + cur_elm->appendChild (new GenericURL (m_document, mrl)); + line = textstream.readLine (); + } while (!line.isNull ()); /* TODO && m_document.size () < 1024 / * support 1k entries * /);*/ + } +} + +KDE_NO_EXPORT void URLSource::kioData (KIO::Job * job, const QByteArray & d) { + SharedPtr <ResolveInfo> rinfo = m_resolve_info; + while (rinfo && rinfo->job != job) + rinfo = rinfo->next; + if (!rinfo) { + kdWarning () << "Spurious kioData" << endl; + return; + } + int size = rinfo->data.size (); + int newsize = size + d.size (); + if (!size) { // first data + int accuraty = 0; + KMimeType::Ptr mime = KMimeType::findByContent (d, &accuraty); + if (!mime || + !mime->name ().startsWith (QString ("text/")) || + (newsize > 4 && !strncmp (d.data (), "RIFF", 4))) { + newsize = 0; + kdDebug () << "URLSource::kioData: " << mime->name () << accuraty << endl; + } + } + //kdDebug () << "URLSource::kioData: " << newsize << endl; + if (newsize <= 0 || newsize > 200000) { + rinfo->data.resize (0); + rinfo->job->kill (false); + m_player->setLoaded (100); + } else { + rinfo->data.resize (newsize); + memcpy (rinfo->data.data () + size, d.data (), newsize - size); + m_player->setLoaded (++rinfo->progress); + } +} + +KDE_NO_EXPORT void URLSource::kioMimetype (KIO::Job * job, const QString & mimestr) { + SharedPtr <ResolveInfo> rinfo = m_resolve_info; + while (rinfo && rinfo->job != job) + rinfo = rinfo->next; + if (!rinfo) { + kdWarning () << "Spurious kioData" << endl; + return; + } + if (rinfo->resolving_mrl) + rinfo->resolving_mrl->mrl ()->mimetype = mimestr; + if (!rinfo->resolving_mrl || !isPlayListMime (mimestr)) + job->kill (false); +} + +KDE_NO_EXPORT void URLSource::kioResult (KIO::Job * job) { + SharedPtr <ResolveInfo> previnfo, rinfo = m_resolve_info; + while (rinfo && rinfo->job != job) { + previnfo = rinfo; + rinfo = rinfo->next; + } + if (!rinfo) { + kdWarning () << "Spurious kioData" << endl; + return; + } + m_player->updateStatus (""); + m_player->setLoaded (100); + if (previnfo) + previnfo->next = rinfo->next; + else + m_resolve_info = rinfo->next; + QTextStream textstream (rinfo->data, IO_ReadOnly); + if (rinfo->resolving_mrl) { + if (isPlayListMime (rinfo->resolving_mrl->mrl ()->mimetype)) + read (rinfo->resolving_mrl, textstream); + rinfo->resolving_mrl->mrl ()->resolved = true; + rinfo->resolving_mrl->undefer (); + } + static_cast <View *> (m_player->view())->controlPanel()->setPlaying (false); +} + +void URLSource::playCurrent () { + Mrl *mrl = m_back_request + ? m_back_request->mrl () + : m_current ? m_current->mrl () : NULL; + if (mrl && mrl->active () && (!mrl->isPlayable () || !mrl->resolved)) + // an async playCurrent() call (eg. backend is up & running), ignore + return; + Source::playCurrent (); +} + +void URLSource::play () { + Source::play (); +} + +bool URLSource::requestPlayURL (NodePtr mrl) { + if (m_document.ptr () != mrl->mrl ()->linkNode ()) { + KURL base = m_document->mrl ()->src; + KURL dest = mrl->mrl ()->linkNode ()->absolutePath (); + // 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 + !kapp->authorizeURLAction ("redirect", base, dest)) { + kdWarning () << "requestPlayURL from document " << base << " to play " << dest << " is not allowed" << endl; + return false; + } + } + return Source::requestPlayURL (mrl); +} + +void URLSource::setURL (const KURL & url) { + Source::setURL (url); + Mrl *mrl = document ()->mrl (); + if (!url.isEmpty () && url.isLocalFile () && mrl->mimetype.isEmpty ()) { + KMimeType::Ptr mimeptr = KMimeType::findByURL (url); + if (mimeptr) + mrl->mimetype = mimeptr->name (); + } +} + +bool URLSource::resolveURL (NodePtr m) { + Mrl * mrl = m->mrl (); + if (!mrl || mrl->src.isEmpty ()) + return true; + int depth = 0; + for (NodePtr e = m->parentNode (); e; e = e->parentNode ()) + ++depth; + if (depth > 40) + return true; + KURL url (mrl->absolutePath ()); + QString mimestr = mrl->mimetype; + if (mimestr == "application/x-shockwave-flash" || + mimestr == "application/futuresplash") + return true; // FIXME + bool maybe_playlist = isPlayListMime (mimestr); + kdDebug () << "resolveURL " << mrl->absolutePath () << " " << mimestr << endl; + if (url.isLocalFile ()) { + QFile file (url.path ()); + if (!file.exists ()) { + kdWarning () << "resolveURL " << url.path() << " not found" << endl; + return true; + } + if (mimestr.isEmpty ()) { + KMimeType::Ptr mimeptr = KMimeType::findByURL (url); + if (mimeptr) { + mrl->mimetype = mimeptr->name (); + maybe_playlist = isPlayListMime (mrl->mimetype); // get new mime + } + } + if (maybe_playlist && file.size () < 2000000 && file.open (IO_ReadOnly)) { + char databuf [512]; + int nr_bytes = file.readBlock (databuf, 512); + if (nr_bytes > 3) { + int accuraty = 0; + KMimeType::Ptr mime = KMimeType::findByContent (QCString (databuf, nr_bytes), &accuraty); + if ((mime && !mime->name().startsWith (QString("text/"))) || + !strncmp (databuf, "RIFF", 4)) { + return true; + } + kdDebug () << "mime: " << (mime ? mime->name (): QString("null")) << endl; + } + file.reset (); + QTextStream textstream (&file); + read (m, textstream); + } + } else if ((maybe_playlist && + url.protocol ().compare (QString ("mms")) && + url.protocol ().compare (QString ("rtsp")) && + url.protocol ().compare (QString ("rtp"))) || + (mimestr.isEmpty () && + (url.protocol ().startsWith (QString ("http")) || + url.protocol () == QString::fromLatin1 ("media") || + url.protocol () == QString::fromLatin1 ("remote")))) { + KIO::Job * job = KIO::get (url, false, false); + job->addMetaData ("PropagateHttpHeader", "true"); + job->addMetaData ("errorPage", "false"); + m_resolve_info = new ResolveInfo (m, job, m_resolve_info); + connect (m_resolve_info->job, SIGNAL(data(KIO::Job*,const QByteArray&)), + this, SLOT (kioData (KIO::Job *, const QByteArray &))); + //connect( m_job, SIGNAL(connected(KIO::Job*)), + // this, SLOT(slotConnected(KIO::Job*))); + connect(m_resolve_info->job, SIGNAL(mimetype(KIO::Job*,const QString&)), + this, SLOT (kioMimetype (KIO::Job *, const QString &))); + connect (m_resolve_info->job, SIGNAL (result (KIO::Job *)), + this, SLOT (kioResult (KIO::Job *))); + static_cast <View *> (m_player->view ())->controlPanel ()->setPlaying (true); + m_player->updateStatus (i18n ("Connecting")); + m_player->setLoaded (0); + return false; // wait for result .. + } + return true; +} + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + static KStaticDeleter <DataCache> dataCacheDeleter; + static DataCache * memory_cache; +} + +void DataCache::add (const QString & url, const QByteArray & data) { + QByteArray bytes; + bytes.duplicate (data); + cache_map.insert (url, bytes); + preserve_map.erase (url); + emit preserveRemoved (url); +} + +bool DataCache::get (const QString & url, QByteArray & data) { + DataMap::const_iterator it = cache_map.find (url); + if (it != cache_map.end ()) { + data.duplicate (it.data ()); + return true; + } + return false; +} + +bool DataCache::preserve (const QString & url) { + PreserveMap::const_iterator it = preserve_map.find (url); + if (it == preserve_map.end ()) { + preserve_map.insert (url, true); + return true; + } + return false; +} + +bool DataCache::isPreserved (const QString & url) { + return preserve_map.find (url) != preserve_map.end (); +} + +bool DataCache::unpreserve (const QString & url) { + const PreserveMap::iterator it = preserve_map.find (url); + if (it == preserve_map.end ()) + return false; + preserve_map.erase (it); + emit preserveRemoved (url); + return true; +} + +RemoteObjectPrivate::RemoteObjectPrivate (RemoteObject * r) + : job (0L), remote_object (r), preserve_wait (false) { + if (!memory_cache) + dataCacheDeleter.setObject (memory_cache, new DataCache); +} + +RemoteObjectPrivate::~RemoteObjectPrivate () { + clear (); +} + +KDE_NO_EXPORT bool RemoteObjectPrivate::download (const QString & str) { + url = str; + KURL kurl (str); + if (kurl.isLocalFile ()) { + QFile file (kurl.path ()); + if (file.exists () && file.open (IO_ReadOnly)) { + data = file.readAll (); + file.close (); + } + remote_object->remoteReady (data); + return true; + } + if (memory_cache->get (str, data)) { + //kdDebug () << "download found in cache " << str << endl; + remote_object->remoteReady (data); + return true; + } + if (memory_cache->preserve (str)) { + //kdDebug () << "downloading " << str << endl; + job = KIO::get (kurl, false, false); + connect (job, SIGNAL (data (KIO::Job *, const QByteArray &)), + this, SLOT (slotData (KIO::Job *, const QByteArray &))); + connect (job, SIGNAL (result (KIO::Job *)), + this, SLOT (slotResult (KIO::Job *))); + connect (job, SIGNAL (mimetype (KIO::Job *, const QString &)), + this, SLOT (slotMimetype (KIO::Job *, const QString &))); + } else { + //kdDebug () << "download preserved " << str << endl; + connect (memory_cache, SIGNAL (preserveRemoved (const QString &)), + this, SLOT (cachePreserveRemoved (const QString &))); + preserve_wait = true; + } + return false; +} + +KDE_NO_EXPORT void RemoteObjectPrivate::clear () { + if (job) { + job->kill (); // quiet, no result signal + job = 0L; + memory_cache->unpreserve (url); + } else if (preserve_wait) { + disconnect (memory_cache, SIGNAL (preserveRemoved (const QString &)), + this, SLOT (cachePreserveRemoved (const QString &))); + preserve_wait = false; + } +} + +KDE_NO_EXPORT void RemoteObjectPrivate::slotResult (KIO::Job * kjob) { + if (!kjob->error ()) + memory_cache->add (url, data); + else + data.resize (0); + job = 0L; // signal KIO::Job::result deletes itself + remote_object->remoteReady (data); +} + +KDE_NO_EXPORT +void RemoteObjectPrivate::cachePreserveRemoved (const QString & str) { + if (str == url && !memory_cache->isPreserved (str)) { + preserve_wait = false; + disconnect (memory_cache, SIGNAL (preserveRemoved (const QString &)), + this, SLOT (cachePreserveRemoved (const QString &))); + download (str); + } +} + +KDE_NO_EXPORT +void RemoteObjectPrivate::slotData (KIO::Job*, const QByteArray& qb) { + if (qb.size ()) { + int old_size = data.size (); + data.resize (old_size + qb.size ()); + memcpy (data.data () + old_size, qb.data (), qb.size ()); + } +} + +KDE_NO_EXPORT +void RemoteObjectPrivate::slotMimetype (KIO::Job *, const QString & m) { + mime = m; +} + +KDE_NO_CDTOR_EXPORT RemoteObject::RemoteObject () + : d (new RemoteObjectPrivate (this)) {} + +KDE_NO_CDTOR_EXPORT RemoteObject::~RemoteObject () { + delete d; +} + +/** + * abort previous wget job + */ +KDE_NO_EXPORT void RemoteObject::killWGet () { + d->clear (); // assume data is invalid +} + +/** + * Gets contents from url and puts it in m_data + */ +KDE_NO_EXPORT bool RemoteObject::wget (const QString & url) { + clear (); + return d->download (url); +} + +KDE_NO_EXPORT QString RemoteObject::mimetype () { + if (d->data.size () > 0 && d->mime.isEmpty ()) { + int accuraty; + KMimeType::Ptr mime = KMimeType::findByContent (d->data, &accuraty); + if (mime) + d->mime = mime->name (); + } + return d->mime; +} + +KDE_NO_EXPORT void RemoteObject::clear () { + killWGet (); + d->url.truncate (0); + d->mime.truncate (0); + d->data.resize (0); +} + +KDE_NO_EXPORT bool RemoteObject::downloading () const { + return !!d->job; +} + +//----------------------------------------------------------------------------- + +#include "kmplayerpartbase.moc" +#include "kmplayersource.moc" diff --git a/src/kmplayerpartbase.h b/src/kmplayerpartbase.h new file mode 100644 index 0000000..206f71e --- /dev/null +++ b/src/kmplayerpartbase.h @@ -0,0 +1,298 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef KMPLAYERPARTBASE_H +#define KMPLAYERPARTBASE_H + +#include <config.h> + +#include "kmplayer_def.h" + +#include <qobject.h> +#include <qguardedptr.h> +#include <qstringlist.h> +#include <qmap.h> + +#include <dcopobject.h> +#include <kmediaplayer/player.h> +#include <kurl.h> + +#include "kmplayerview.h" +#include "kmplayersource.h" + + +class KAboutData; +class KInstance; +class KActionCollection; +class KBookmarkMenu; +class KConfig; +class QIODevice; +class QTextStream; +class QListViewItem; + +namespace KIO { + class Job; +} + +namespace KMPlayer { + +class PartBase; +class Process; +class MPlayer; +class BookmarkOwner; +class BookmarkManager; +class MEncoder; +class MPlayerDumpstream; +class FFMpeg; +class Xine; +class Settings; + +/* + * Source from URLs + */ +class KMPLAYER_EXPORT URLSource : public Source { + Q_OBJECT +public: + URLSource (PartBase * player, const KURL & url = KURL ()); + virtual ~URLSource (); + + virtual void dimensions (int & w, int & h); + virtual bool hasLength (); + virtual QString prettyName (); + virtual void reset (); + virtual void setURL (const KURL & url); +public slots: + virtual void init (); + virtual void activate (); + virtual void deactivate (); + virtual void playCurrent (); + virtual void forward (); + virtual void backward (); + virtual void jump (NodePtr e); + void play (); +private slots: + void kioData (KIO::Job *, const QByteArray &); + void kioMimetype (KIO::Job *, const QString &); + void kioResult (KIO::Job *); +protected: + virtual bool requestPlayURL (NodePtr mrl); + virtual bool resolveURL (NodePtr mrl); +private: + void read (NodePtr mrl, QTextStream &); + void stopResolving (); + struct ResolveInfo { + ResolveInfo (NodePtr mrl, KIO::Job * j, SharedPtr <ResolveInfo> & n) + : resolving_mrl (mrl), job (j), progress (0), next (n) {} + NodePtrW resolving_mrl; + KIO::Job * job; + QByteArray data; + int progress; + SharedPtr <ResolveInfo> next; + }; + SharedPtr <ResolveInfo> m_resolve_info; + bool activated; // 'solve' an singleShot race w/ cmdline url's +}; + +/* + * KDE's KMediaPlayer::Player implementation and base for KMPlayerPart + */ +class KMPLAYER_EXPORT PartBase : public KMediaPlayer::Player { + Q_OBJECT + K_DCOP +public: + typedef QMap <QString, Process *> ProcessMap; + PartBase (QWidget * parent, const char * wname,QObject * objectParent, const char * name, KConfig *); + ~PartBase (); + void init (KActionCollection * = 0L); + virtual KMediaPlayer::View* view (); + static KAboutData* createAboutData (); + + Settings * settings () const { return m_settings; } + void keepMovieAspect (bool); + KURL url () const { return m_sources ["urlsource"]->url (); } + void setURL (const KURL & url) { m_sources ["urlsource"]->setURL (url); } + + /* Changes the backend process */ + void setProcess (const char *); + bool setProcess (Mrl *mrl); + void setRecorder (const char *); + + /* Changes the source, + * calls init() and reschedules an activate() on the source + * */ + void setSource (Source * source); + void connectPanel (ControlPanel * panel); + void connectPlaylist (PlayListView * playlist); + void connectInfoPanel (InfoWindow * infopanel); + void connectSource (Source * old_source, Source * source); + Process * process () const { return m_process; } + Process * recorder () const { return m_recorder; } + Source * source () const { return m_source; } + QMap <QString, Process *> & players () { return m_players; } + QMap <QString, Process *> & recorders () { return m_recorders; } + QMap <QString, Source *> & sources () { return m_sources; } + KConfig * config () const { return m_config; } + bool mayResize () const { return !m_noresize; } + void updatePlayerMenu (ControlPanel *); + void updateInfo (const QString & msg); + void updateStatus (const QString & msg); +#ifdef HAVE_DBUS + void setServiceName (const QString & srv) { m_service = srv; } + QString serviceName () const { return m_service; } +#endif + + // these are called from Process + void changeURL (const QString & url); + void updateTree (bool full=true, bool force=false); + void setLanguages (const QStringList & alang, const QStringList & slang); +public slots: + virtual bool openURL (const KURL & url); + virtual bool openURL (const KURL::List & urls); + virtual bool closeURL (); + virtual void pause (void); + virtual void play (void); + virtual void stop (void); + void record (); + virtual void seek (unsigned long msec); + void adjustVolume (int incdec); + bool playing () const; + void showConfigDialog (); + void showPlayListWindow (); + void slotPlayerMenu (int); + void back (); + void forward (); + void addBookMark (const QString & title, const QString & url); + void volumeChanged (int); + void increaseVolume (); + void decreaseVolume (); + void setPosition (int position, int length); + virtual void setLoaded (int percentage); +public: + virtual bool isSeekable (void) const; + virtual unsigned long position (void) const; + virtual bool hasLength (void) const; + virtual unsigned long length (void) const; +k_dcop: + void toggleFullScreen (); + bool isPlaying (); +signals: + void sourceChanged (KMPlayer::Source * old, KMPlayer::Source * nw); + void sourceDimensionChanged (); + void loading (int percentage); + void urlAdded (const QString & url); + void urlChanged (const QString & url); + void processChanged (const char *); + void treeChanged (int id, NodePtr root, NodePtr, bool select, bool open); + void treeUpdated (); + void infoUpdated (const QString & msg); + void statusUpdated (const QString & msg); + void languagesUpdated(const QStringList & alang, const QStringList & slang); + void audioIsSelected (int id); + void subtitleIsSelected (int id); + void positioned (int pos, int length); +protected: + bool openFile(); + virtual void timerEvent (QTimerEvent *); +protected slots: + void posSliderPressed (); + void posSliderReleased (); + void positionValueChanged (int val); + void contrastValueChanged (int val); + void brightnessValueChanged (int val); + void hueValueChanged (int val); + void saturationValueChanged (int val); + void sourceHasChangedAspects (); + void fullScreen (); + void playListItemClicked (QListViewItem *); + void playListItemExecuted (QListViewItem *); + virtual void playingStarted (); + virtual void playingStopped (); + void recordingStarted (); + void recordingStopped (); + void settingsChanged (); + void audioSelected (int); + void subtitleSelected (int); +protected: + KConfig * m_config; + QGuardedPtr <View> m_view; + QMap <QString, QString> temp_backends; + Settings * m_settings; + Process * m_process; + Process * m_recorder; + Source * m_source; + ProcessMap m_players; + ProcessMap m_recorders; + QMap <QString, Source *> m_sources; + BookmarkManager * m_bookmark_manager; + BookmarkOwner * m_bookmark_owner; + KBookmarkMenu * m_bookmark_menu; +#ifdef HAVE_DBUS + QString m_service; +#endif + int m_record_timer; + int m_update_tree_timer; + bool m_noresize : 1; + bool m_auto_controls : 1; + bool m_use_slave : 1; + bool m_bPosSliderPressed : 1; + bool m_in_update_tree : 1; + bool m_update_tree_full : 1; +}; + +class KMPLAYER_NO_EXPORT DataCache : public QObject { + Q_OBJECT + typedef QMap <QString, QByteArray> DataMap; + typedef QMap <QString, bool> PreserveMap; + DataMap cache_map; + PreserveMap preserve_map; +public: + DataCache () {} + ~DataCache () {} + void add (const QString &, const QByteArray &); + bool get (const QString &, QByteArray &); + bool preserve (const QString &); + bool unpreserve (const QString &); + bool isPreserved (const QString &); +signals: + void preserveRemoved (const QString &); // ready or canceled +}; + +class KMPLAYER_NO_EXPORT RemoteObjectPrivate : public QObject { + Q_OBJECT +public: + RemoteObjectPrivate (RemoteObject * r); + ~RemoteObjectPrivate (); + bool download (const QString &); + void clear (); + KIO::Job * job; + QString url; + QByteArray data; + QString mime; +private slots: + void slotResult (KIO::Job*); + void slotData (KIO::Job*, const QByteArray& qb); + void slotMimetype (KIO::Job * job, const QString & mimestr); + void cachePreserveRemoved (const QString &); +private: + RemoteObject * remote_object; + bool preserve_wait; +}; + +} // namespace + +#endif diff --git a/src/kmplayerpartui.rc b/src/kmplayerpartui.rc new file mode 100644 index 0000000..271365f --- /dev/null +++ b/src/kmplayerpartui.rc @@ -0,0 +1,19 @@ +<!DOCTYPE kpartgui> +<kpartgui name="kmplayer" version="8"> +<MenuBar> + <Menu name="view"><text>&View</text> + <Action name="play"/> + <Action name="pause"/> + <Action name="stop"/> + <Action name="edit_playlist_item"/> + </Menu> +</MenuBar> +<ActionProperties> + <Action shortcut="F2" name="edit_playlist_item"/> +</ActionProperties> +<Toolbar name="mainToolBar"><text></text> + <Action name="play"/> + <Action name="pause"/> + <Action name="stop"/> +</Toolbar> +</kpartgui> diff --git a/src/kmplayerplaylist.cpp b/src/kmplayerplaylist.cpp new file mode 100644 index 0000000..e2db4f3 --- /dev/null +++ b/src/kmplayerplaylist.cpp @@ -0,0 +1,1842 @@ +/** + * Copyright (C) 2004 by Koos Vriezen <[email protected]> + * + * 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 <config.h> +#include <time.h> + +#include <qtextstream.h> +#include <kdebug.h> +#include <kurl.h> +#ifdef HAVE_EXPAT +#include <expat.h> +#endif +#ifdef HAVE_CAIRO +# include <cairo.h> +#endif +#include "kmplayerplaylist.h" +#include "kmplayer_asx.h" +#include "kmplayer_atom.h" +#include "kmplayer_rp.h" +#include "kmplayer_rss.h" +#include "kmplayer_smil.h" +#include "kmplayer_xspf.h" + +#ifdef SHAREDPTR_DEBUG +int shared_data_count; +#endif + +using namespace KMPlayer; + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + Node * fromXMLDocumentTag (NodePtr & d, const QString & tag) { + const char * const name = tag.latin1 (); + if (!strcmp (name, "smil")) + return new SMIL::Smil (d); + else if (!strcasecmp (name, "asx")) + return new ASX::Asx (d); + else if (!strcasecmp (name, "imfl")) + return new RP::Imfl (d); + else if (!strcasecmp (name, "rss")) + return new RSS::Rss (d); + else if (!strcasecmp (name, "feed")) + return new ATOM::Feed (d); + else if (!strcasecmp (name, "playlist")) + return new XSPF::Playlist (d); + else if (!strcasecmp (name, "url")) + return new GenericURL (d, QString ()); + else if (!strcasecmp (name, "mrl") || + !strcasecmp (name, "document")) + return new GenericMrl (d); + return 0L; + } + +//----------------------------------------------------------------------------- + + struct XMLStringlet { + const QString str; + XMLStringlet (const QString & s) : str (s) {} + }; +} // namespace + +QTextStream & operator << (QTextStream & out, const XMLStringlet & txt) { + int len = int (txt.str.length ()); + for (int i = 0; i < len; ++i) { + if (txt.str [i] == QChar ('<')) { + out << "<"; + } else if (txt.str [i] == QChar ('>')) { + out << ">"; + } else if (txt.str [i] == QChar ('"')) { + out << """; + } else if (txt.str [i] == QChar ('&')) { + out << "&"; + } else + out << txt.str [i]; + } + return out; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +Connection::Connection (NodeRefListPtr ls, NodePtr node, NodePtr inv) + : connectee (inv), listeners (ls) { + if (listeners) { + NodeRefItemPtr nci = new NodeRefItem (node); + listeners->append (nci); + listen_item = nci; + } +} + +KDE_NO_EXPORT void Connection::disconnect () { + if (listen_item && listeners) + listeners->remove (listen_item); + listen_item = 0L; + listeners = 0L; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +TimerInfo::TimerInfo (NodePtr n, unsigned id, struct timeval & tv, int ms) + : node (n), event_id (id), timeout (tv), milli_sec (ms) {} + +//----------------------------------------------------------------------------- + +Matrix::Matrix () : a (1.0), b (0.0), c (0.0), d (1.0), tx (0), ty (0) {} + +Matrix::Matrix (const Matrix & m) + : a (m.a), b (m.b), c (m.c), d (m.d), tx (m.tx), ty (m.ty) {} + +Matrix::Matrix (Single xoff, Single yoff, float xscale, float yscale) + : a (xscale), b (0.0), c (0.0), d (yscale), tx (xoff), ty (yoff) {} + +void Matrix::getXY (Single & x, Single & y) const { + x = Single (x * a) + tx; + y = Single (y * d) + ty; +} + +void Matrix::getXYWH (Single & x, Single & y, Single & w, Single & h) const { + getXY (x, y); + w *= a; + h *= d; +} + +void Matrix::invXYWH (Single & x, Single & y, Single & w, Single & h) const { + if (a > 0.00001 && d > 0.00001) { + w /= a; + h /= d; + x = Single ((x - tx) / a); + y = Single ((y - ty) / d); + } else { + kdWarning () << "Not invering " << a << ", " << d << " scale" << endl; + } +} + +void Matrix::transform (const Matrix & matrix) { + // TODO: rotate + a *= matrix.a; + d *= matrix.d; + tx = Single (tx * matrix.a) + matrix.tx; + ty = Single (ty * matrix.d) + matrix.ty; +} + +void Matrix::scale (float sx, float sy) { + a *= sx; + d *= sy; + tx *= sx; + ty *= sy; +} + +void Matrix::translate (Single x, Single y) { + tx += x; + ty += y; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT Node::Node (NodePtr & d, short _id) + : m_doc (d), state (state_init), id (_id), + auxiliary_node (false), editable (true) {} + +Node::~Node () { + clear (); +} + +Document * Node::document () { + return convertNode <Document> (m_doc); +} + +Mrl * Node::mrl () { + return 0L; +} + +const char * Node::nodeName () const { + return "node"; +} + +void Node::setState (State nstate) { + if (state != nstate) { + State old = state; + state = nstate; + if (document ()->notify_listener) + document()->notify_listener->stateElementChanged (this, old, state); + } +} + +bool Node::expose () const { + return true; +} + +void Node::activate () { + //kdDebug () << nodeName () << " Node::activate" << endl; + setState (state_activated); + if (firstChild ()) + firstChild ()->activate (); // activate only the first + else + finish (); // a quicky :-) +} + +void Node::begin () { + if (active ()) { + setState (state_began); + } else + kdError () << nodeName() << " begin call on not active element" << endl; +} + +void Node::defer () { + if (active ()) { + setState (state_deferred); + } else + kdError () << "Node::defer () call on not activated element" << endl; +} + +void Node::undefer () { + if (state == state_deferred) { + setState (state_activated); + activate (); + } else + kdWarning () <<"Node::undefer () call on not deferred element"<< endl; +} + +void Node::finish () { + if (active ()) { + setState (state_finished); + if (m_parent) + m_parent->childDone (this); + else + deactivate (); // document deactivates itself on finish + } else + kdWarning () <<"Node::finish () call on not active element"<< endl; +} + +void Node::deactivate () { + //kdDebug () << nodeName () << " Node::deactivate" << endl; + bool need_finish (unfinished ()); + setState (state_deactivated); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e->state > state_init && e->state < state_deactivated) + e->deactivate (); + else + break; // remaining not yet activated + } + if (need_finish && m_parent) + m_parent->childDone (this); +} + +void Node::reset () { + //kdDebug () << nodeName () << " Node::reset" << endl; + if (active ()) + deactivate (); + setState (state_init); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { + if (e->state != state_init) + e->reset (); + // else + // break; // rest not activated yet + } +} + +void Node::childBegan (NodePtr /*child*/) { +} + +void Node::childDone (NodePtr child) { + //kdDebug () << nodeName () << " Node::childDone" << endl; + if (unfinished ()) { + if (child->state == state_finished) + child->deactivate (); + if (child->nextSibling ()) + child->nextSibling ()->activate (); + else + finish (); // we're done + } +} + +void Node::clear () { + clearChildren (); +} + +void Node::clearChildren () { + if (m_doc) + document()->m_tree_version++; + while (m_first_child != m_last_child) { + // avoid stack abuse with 10k children derefing each other + m_last_child->m_parent = 0L; + m_last_child = m_last_child->m_prev; + m_last_child->m_next = 0L; + } + if (m_first_child) + m_first_child->m_parent = 0L; + m_first_child = m_last_child = 0L; +} + +void Node::appendChild (NodePtr c) { + document()->m_tree_version++; + ASSERT (!c->parentNode ()); + TreeNode<Node>::appendChild (c); +} + +void Node::insertBefore (NodePtr c, NodePtr b) { + if (!b) { + appendChild (c); + } else { + ASSERT (!c->parentNode ()); + document()->m_tree_version++; + if (b->m_prev) { + b->m_prev->m_next = c; + c->m_prev = b->m_prev; + } else { + c->m_prev = 0L; + m_first_child = c; + } + b->m_prev = c; + c->m_next = b; + c->m_parent = this; + } +} + +void Node::removeChild (NodePtr c) { + document()->m_tree_version++; + TreeNode <Node>::removeChild (c); +} + +KDE_NO_EXPORT void Node::replaceChild (NodePtr _new, NodePtr old) { + document()->m_tree_version++; + if (old->m_prev) { + old->m_prev->m_next = _new; + _new->m_prev = old->m_prev; + old->m_prev = 0L; + } else { + _new->m_prev = 0L; + m_first_child = _new; + } + if (old->m_next) { + old->m_next->m_prev = _new; + _new->m_next = old->m_next; + old->m_next = 0L; + } else { + _new->m_next = 0L; + m_last_child = _new; + } + _new->m_parent = this; + old->m_parent = 0L; +} + +NodePtr Node::childFromTag (const QString &) { + return NodePtr (); +} + +KDE_NO_EXPORT void Node::characterData (const QString & s) { + document()->m_tree_version++; + if (!m_last_child || m_last_child->id != id_node_text) + appendChild (new TextNode (m_doc, s)); + else + convertNode <TextNode> (m_last_child)->appendText (s); +} + +void Node::normalize () { + NodePtr e = firstChild (); + while (e) { + NodePtr tmp = e->nextSibling (); + if (!e->isElementNode () && e->id == id_node_text) { + QString val = e->nodeValue ().simplifyWhiteSpace (); + if (val.isEmpty ()) + removeChild (e); + else + convertNode <TextNode> (e)->setText (val); + } else + e->normalize (); + e = tmp; + } +} + +static void getInnerText (const NodePtr p, QTextOStream & out) { + for (NodePtr e = p->firstChild (); e; e = e->nextSibling ()) { + if (e->id == id_node_text || e->id == id_node_cdata) + out << e->nodeValue (); + else + getInnerText (e, out); + } +} + +QString Node::innerText () const { + QString buf; + QTextOStream out (&buf); + getInnerText (m_self, out); + return buf; +} + +static void getOuterXML (const NodePtr p, QTextOStream & out, int depth) { + if (!p->isElementNode ()) { // #text or #cdata + if (p->id == id_node_cdata) + out << "<![CDATA[" << p->nodeValue () << "]]>" << QChar ('\n'); + else + out << XMLStringlet (p->nodeValue ()) << QChar ('\n'); + } else { + Element * e = convertNode <Element> (p); + QString indent (QString ().fill (QChar (' '), depth)); + out << indent << QChar ('<') << XMLStringlet (e->nodeName ()); + for (AttributePtr a = e->attributes()->first(); a; a = a->nextSibling()) + out << " " << XMLStringlet (a->name ().toString ()) << + "=\"" << XMLStringlet (a->value ()) << "\""; + if (e->hasChildNodes ()) { + out << QChar ('>') << QChar ('\n'); + for (NodePtr c = e->firstChild (); c; c = c->nextSibling ()) + getOuterXML (c, out, depth + 1); + out << indent << QString("</") << XMLStringlet (e->nodeName()) << + QChar ('>') << QChar ('\n'); + } else + out << QString ("/>") << QChar ('\n'); + } +} + +QString Node::innerXML () const { + QString buf; + QTextOStream out (&buf); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + getOuterXML (e, out, 0); + return buf; +} + +QString Node::outerXML () const { + QString buf; + QTextOStream out (&buf); + getOuterXML (m_self, out, 0); + return buf; +} + +Node::PlayType Node::playType () { + return play_type_none; +} + +void Node::opened () {} + +void Node::closed () {} + +NodeRefListPtr Node::listeners (unsigned int /*event_id*/) { + return NodeRefListPtr (); +} + +bool Node::handleEvent (EventPtr /*event*/) { return false; } + +KDE_NO_EXPORT void Node::propagateEvent (EventPtr event) { + NodeRefListPtr nl = listeners (event->id ()); + if (nl) + for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) + if (c->data) + c->data->handleEvent (event); +} + +void Node::accept (Visitor * v) { + v->visit (this); +} + +KDE_NO_EXPORT +ConnectionPtr Node::connectTo (NodePtr node, unsigned int evt_id) { + NodeRefListPtr nl = listeners (evt_id); + if (nl) + return ConnectionPtr (new Connection (nl, node, this)); + return ConnectionPtr (); +} + +QString Node::nodeValue () const { + return QString (); +} + +SurfacePtr Node::getSurface (NodePtr) { + return 0L; +} + +//----------------------------------------------------------------------------- + +RefNode::RefNode (NodePtr & d, NodePtr ref) + : Node (d) { + setRefNode (ref); +} + +void RefNode::setRefNode (const NodePtr ref) { + ref_node = ref; + if (ref_node) + tag_name = QString ("&%1").arg (ref_node->nodeName ()); +} + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + struct KMPLAYER_NO_EXPORT ParamValue { + QString val; + QStringList * modifications; + ParamValue (const QString & v) : val (v), modifications (0L) {} + ~ParamValue () { delete modifications; } + QString value (); + void setValue (const QString & v) { val = v; } + }; + typedef QMap <TrieString, ParamValue *> ParamMap; + class KMPLAYER_NO_EXPORT ElementPrivate { + public: + ~ElementPrivate (); + ParamMap params; + void clear (); + }; +} + +KDE_NO_EXPORT QString ParamValue::value () { + return modifications && modifications->size () + ? modifications->back () : val; +} + +KDE_NO_CDTOR_EXPORT ElementPrivate::~ElementPrivate () { + clear (); +} + +KDE_NO_EXPORT void ElementPrivate::clear () { + const ParamMap::iterator e = params.end (); + for (ParamMap::iterator i = params.begin (); i != e; ++i) + delete i.data (); + params.clear (); +} + +Element::Element (NodePtr & d, short id) + : Node (d, id), m_attributes (new AttributeList), d (new ElementPrivate) {} + +Element::~Element () { + delete d; +} + +void Element::setParam (const TrieString ¶m, const QString &val, int *mid) { + ParamValue * pv = d->params [param]; + if (!pv) { + pv = new ParamValue (mid ? QString() : val); + d->params.insert (param, pv); + } + if (mid) { + if (!pv->modifications) + pv->modifications = new QStringList; + if (*mid >= 0 && *mid < int (pv->modifications->size ())) { + (*pv->modifications) [*mid] = val; + } else { + *mid = pv->modifications->size (); + pv->modifications->push_back (val); + } + } else + pv->setValue (val); + parseParam (param, val); +} + +QString Element::param (const TrieString & name) { + ParamValue * pv = d->params [name]; + if (pv) + return pv->value (); + return QString (); +} + +void Element::resetParam (const TrieString & param, int mid) { + ParamValue * pv = d->params [param]; + if (pv && pv->modifications) { + if (int (pv->modifications->size ()) > mid && mid > -1) { + (*pv->modifications) [mid] = QString (); + while (pv->modifications->size () > 0 && + pv->modifications->back ().isNull ()) + pv->modifications->pop_back (); + } + QString val = pv->value (); + if (pv->modifications->size () == 0) { + delete pv->modifications; + pv->modifications = 0L; + val = pv->value (); + if (val.isNull ()) { + delete pv; + d->params.remove (param); + } + } + parseParam (param, val); + } else + kdError () << "resetting " << param.toString() << " that doesn't exists" << endl; +} + +void Element::setAttribute (const TrieString & name, const QString & value) { + for (AttributePtr a = m_attributes->first (); a; a = a->nextSibling ()) + if (name == a->name ()) { + a->setValue (value); + return; + } + m_attributes->append (new Attribute (name, value)); +} + +QString Element::getAttribute (const TrieString & name) { + for (AttributePtr a = m_attributes->first (); a; a = a->nextSibling ()) + if (name == a->name ()) + return a->value (); + return QString (); +} + +void Element::init () { + d->clear(); + for (AttributePtr a = attributes ()->first (); a; a = a->nextSibling ()) + setParam (a->name (), a->value ()); +} + +void Element::reset () { + d->clear(); + Node::reset (); +} + +void Element::clear () { + m_attributes = new AttributeList; // remove attributes + d->clear(); + Node::clear (); +} + +void Element::setAttributes (AttributeListPtr attrs) { + m_attributes = attrs; +} + +//----------------------------------------------------------------------------- + +Attribute::Attribute (const TrieString & n, const QString & v) + : m_name (n), m_value (v) {} + +void Attribute::setName (const TrieString & n) { + m_name = n; +} + +void Attribute::setValue (const QString & v) { + m_value = v; +} + +//----------------------------------------------------------------------------- + +static bool hasMrlChildren (const NodePtr & e) { + for (NodePtr c = e->firstChild (); c; c = c->nextSibling ()) + if (c->isPlayable () || hasMrlChildren (c)) + return true; + return false; +} + +Mrl::Mrl (NodePtr & d, short id) + : Element (d, id), cached_ismrl_version (~0), + aspect (0), repeat (0), + view_mode (SingleMode), + resolved (false), bookmarkable (true) {} + +Mrl::~Mrl () {} + +Node::PlayType Mrl::playType () { + if (cached_ismrl_version != document()->m_tree_version) { + bool ismrl = !hasMrlChildren (this); + cached_play_type = ismrl ? play_type_unknown : play_type_none; + cached_ismrl_version = document()->m_tree_version; + } + return cached_play_type; +} + +QString Mrl::absolutePath () { + QString path = src; + if (!path.isEmpty()) { + for (NodePtr e = parentNode (); e; e = e->parentNode ()) { + Mrl * mrl = e->mrl (); + if (mrl && !mrl->src.isEmpty () && mrl->src != src) { + path = KURL (mrl->absolutePath (), src).url (); + break; + } + } + } + return path; +} + +NodePtr Mrl::childFromTag (const QString & tag) { + Node * elm = fromXMLDocumentTag (m_doc, tag); + if (elm) + return elm; + return NodePtr (); +} + +Mrl * Mrl::linkNode () { + return this; +} + +Mrl * Mrl::mrl () { + return this; +} + +void Mrl::endOfFile () { + if (state == state_deferred && + !isPlayable () && firstChild ()) { // if backend added child links + state = state_activated; + firstChild ()->activate (); + } else + finish (); +} + +void Mrl::activate () { + resolved |= linkNode ()->resolved; + if (!resolved && document ()->notify_listener) + resolved = document ()->notify_listener->resolveURL (this); + if (!resolved) { + setState (state_deferred); + return; + } else + linkNode ()->resolved = true; + if (!isPlayable ()) { + Element::activate (); + return; + } + setState (state_activated); + begin (); +} + +void Mrl::begin () { + kdDebug () << nodeName () << " Mrl::activate" << endl; + if (document ()->notify_listener) { + if (linkNode () != this) { + linkNode ()->activate (); + if (linkNode ()->unfinished ()) + setState (state_began); + } else if (!src.isEmpty ()) { + if (document ()->notify_listener->requestPlayURL (this)) + setState (state_began); + } else + deactivate (); // nothing to activate + } +} + +SurfacePtr Mrl::getSurface (NodePtr node) { + for (NodePtr p = parentNode (); p; p = p->parentNode ()) + if (p->mrl ()) + return p->getSurface (node); + return 0L; +} + +bool Mrl::handleEvent (EventPtr) { + return false; +} + +void Mrl::parseParam (const TrieString & para, const QString & val) { + if (para == StringPool::attr_src && !src.startsWith ("#")) { + QString abs = absolutePath (); + if (abs != src) + src = val; + else + src = KURL (abs, val).url (); + for (NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->mrl () && c->mrl ()->opener.ptr () == this) { + removeChild (c); + c->reset(); + } + resolved = false; + } +} + +Surface::Surface (NodePtr n, const SRect & r) + : node (n), + bounds (r), + xscale (1.0), yscale (1.0), + background_color (0), + dirty (false) +#ifdef HAVE_CAIRO + , surface (0L) +#endif +{} + +Surface::~Surface() { +#ifdef HAVE_CAIRO + if (surface) + cairo_surface_destroy (surface); +#endif +} + +void Surface::remove () { + Surface *sp = parentNode ().ptr (); + if (sp) { + sp->markDirty (); + sp->removeChild (this); + } +} + +void Surface::markDirty () { + for (Surface *s = this; s; s = s->parentNode ().ptr ()) + s->dirty = true; +} + +//----------------------------------------------------------------------------- + +Postpone::Postpone (NodePtr doc) : m_doc (doc) { + if (m_doc) + m_doc->document ()->timeOfDay (postponed_time); +} + +Postpone::~Postpone () { + if (m_doc) + m_doc->document ()->proceed (postponed_time); +} + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + static NodePtr dummy_element; +} + +Document::Document (const QString & s, PlayListNotify * n) + : Mrl (dummy_element, id_node_document), + notify_listener (n), + m_tree_version (0), + m_PostponedListeners (new NodeRefList), + cur_timeout (-1), intimer (false) { + m_doc = m_self; // just-in-time setting fragile m_self to m_doc + src = s; + editable = false; +} + +Document::~Document () { + kdDebug () << "~Document" << endl; +} + +static NodePtr getElementByIdImpl (NodePtr n, const QString & id, bool inter) { + NodePtr elm; + if (!n->isElementNode ()) + return elm; + Element * e = convertNode <Element> (n); + if (e->getAttribute (StringPool::attr_id) == id) + return n; + for (NodePtr c = e->firstChild (); c; c = c->nextSibling ()) { + if (!inter && c->mrl () && c->mrl ()->opener == n) + continue; + if ((elm = getElementByIdImpl (c, id, inter))) + break; + } + return elm; +} + +NodePtr Document::getElementById (const QString & id) { + return getElementByIdImpl (this, id, true); +} + +NodePtr Document::getElementById (NodePtr n, const QString & id, bool inter) { + return getElementByIdImpl (n, id, inter); +} + +NodePtr Document::childFromTag (const QString & tag) { + Node * elm = fromXMLDocumentTag (m_doc, tag); + if (elm) + return elm; + return 0L; +} + +void Document::dispose () { + clear (); + m_doc = 0L; +} + +void Document::activate () { + first_event_time.tv_sec = 0; + last_event_time = 0; + Mrl::activate (); +} + +void Document::defer () { + if (resolved) + postpone_lock = postpone (); + Mrl::defer (); +} + +void Document::undefer () { + if (!postpone_lock) { + Mrl::undefer (); + } else { + setState (state_activated); + postpone_lock = 0L; + } +} + +void Document::reset () { + Mrl::reset (); + if (timers.first ()) { + if (notify_listener) + notify_listener->setTimeout (-1); + timers.clear (); + } + postpone_lock = 0L; +} + +static inline +int diffTime (const struct timeval & tv1, const struct timeval & tv2) { + //kdDebug () << "diffTime sec:" << ((tv1.tv_sec - tv2.tv_sec) * 1000) << " usec:" << ((tv1.tv_usec - tv2.tv_usec) /1000) << endl; + return (tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) /1000; +} + +static inline void addTime (struct timeval & tv, int ms) { + tv.tv_sec += (tv.tv_usec + ms*1000) / 1000000; + tv.tv_usec = (tv.tv_usec + ms*1000) % 1000000; +} + +void Document::timeOfDay (struct timeval & tv) { + gettimeofday (&tv, 0L); + if (!first_event_time.tv_sec) { + first_event_time = tv; + last_event_time = 0; + } else + last_event_time = diffTime (tv, first_event_time) / 100; +} + +TimerInfoPtrW Document::setTimeout (NodePtr n, int ms, unsigned id) { + if (!notify_listener) + return 0L; + TimerInfoPtr ti = timers.first (); + int pos = 0; + struct timeval tv; + timeOfDay (tv); + addTime (tv, ms); + for (; ti && diffTime (ti->timeout, tv) <= 0; ti = ti->nextSibling ()) { + pos++; + //kdDebug () << "setTimeout tv:" << tv.tv_sec << "." << tv.tv_usec << " " << ti->timeout.tv_sec << "." << ti->timeout.tv_usec << endl; + } + TimerInfo * tinfo = new TimerInfo (n, id, tv, ms); + timers.insertBefore (tinfo, ti); + //kdDebug () << "setTimeout " << ms << " at:" << pos << " tv:" << tv.tv_sec << "." << tv.tv_usec << endl; + if (!postpone_ref && pos == 0 && !intimer) { // timer() does that too + cur_timeout = ms; + notify_listener->setTimeout (ms); + } + return tinfo; +} + +void Document::cancelTimer (TimerInfoPtr tinfo) { + if (!postpone_ref && !intimer && tinfo == timers.first ()) { + //kdDebug () << "cancel first" << endl; + TimerInfoPtr second = tinfo->nextSibling (); + if (second) { + struct timeval now; + timeOfDay (now); + int diff = diffTime (now, second->timeout); + cur_timeout = diff > 0 ? 0 : -diff; + } else + cur_timeout = -1; + notify_listener->setTimeout (cur_timeout); + } + timers.remove (tinfo); +} + +bool Document::timer () { + struct timeval now = { 0, 0 }; // unset + int new_timeout = -1; + TimerInfoPtrW tinfo = timers.first (); // keep use_count on 1 + + intimer = true; + // handle max 100 timeouts with timeout set to now + for (int i = 0; !!tinfo && !postpone_ref && i < 100; ++i) { + if (tinfo && !tinfo->node) { + // some part of document has gone and didn't remove timer + kdError () << "spurious timer" << endl; + for (; tinfo && !tinfo->node; tinfo = timers.first ()) + timers.remove (tinfo); + tinfo = timers.first (); + } + if (!tinfo) + break; + TimerEvent * te = new TimerEvent (tinfo); + EventPtr e (te); + tinfo->node->handleEvent (e); + if (tinfo) { // may be removed from timers and become 0 + if (te->interval) { + TimerInfoPtr tinfo2 (tinfo); // prevent destruction + timers.remove (tinfo); + timeOfDay (now); + int drift = diffTime (now, tinfo2->timeout); + if (drift > tinfo2->milli_sec) { + drift = tinfo2->milli_sec; + //kdWarning() << "time drift" << endl; + } + tinfo2->timeout = now; + addTime (tinfo2->timeout, tinfo2->milli_sec - drift); + TimerInfoPtr ti = timers.first (); + int pos = 0; + for (; ti && diffTime (tinfo2->timeout, ti->timeout) >= 0; ti = ti->nextSibling ()) { + pos++; + } + timers.insertBefore (tinfo2, ti); + } else + timers.remove (tinfo); + } + tinfo = timers.first (); + if (!tinfo) + break; + if (!now.tv_sec) + timeOfDay (now); + int diff = diffTime (now, tinfo->timeout); + new_timeout = diff > 0 ? 0 : -diff; + if (new_timeout > 0) + break; + } + intimer = false; + + // set new timeout to prevent interval timer events + if (notify_listener && !postpone_ref && tinfo) { + if (new_timeout != cur_timeout) { + cur_timeout = new_timeout; + notify_listener->setTimeout (cur_timeout); + } + // else keep the timer, no new setTimeout + } else { + cur_timeout = -1; + notify_listener->setTimeout (-1); // kill timer + } + return false; +} + +PostponePtr Document::postpone () { + if (postpone_ref) + return postpone_ref; + kdDebug () << "postpone" << endl; + if (!intimer && notify_listener) { + cur_timeout = -1; + notify_listener->setTimeout (-1); + } + PostponePtr p = new Postpone (this); + postpone_ref = p; + propagateEvent (new PostponedEvent (true)); + return p; +} + +void Document::proceed (const struct timeval & postponed_time) { + kdDebug () << "proceed" << endl; + if (timers.first () && notify_listener) { + struct timeval now; + timeOfDay (now); + int diff = diffTime (now, postponed_time); + if (diff > 0) { + for (TimerInfoPtr t = timers.first (); t; t = t->nextSibling ()) + addTime (t->timeout, diff); + } + if (!intimer) { // eg. postpone() + proceed() in same timer() + diff = diffTime (timers.first ()->timeout, now); + cur_timeout = diff < 0 ? 0 : diff; + notify_listener->setTimeout (cur_timeout); + } + } + propagateEvent (new PostponedEvent (false)); +} + +SurfacePtr Document::getSurface (NodePtr node) { + if (notify_listener) + return notify_listener->getSurface (node); + return 0L; +} + +NodeRefListPtr Document::listeners (unsigned int id) { + if (id == event_postponed) + return m_PostponedListeners; + return Mrl::listeners (id); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT TextNode::TextNode (NodePtr & d, const QString & s, short i) + : Node (d, i), text (s) {} + +void TextNode::appendText (const QString & s) { + text += s; +} + +QString TextNode::nodeValue () const { + return text; +} + +KDE_NO_EXPORT bool TextNode::expose () const { + return false; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT CData::CData (NodePtr & d, const QString & s) + : TextNode (d, s, id_node_cdata) {} + +//----------------------------------------------------------------------------- + +DarkNode::DarkNode (NodePtr & d, const QString & n, short id) + : Element (d, id), name (n) { +} + +NodePtr DarkNode::childFromTag (const QString & tag) { + return new DarkNode (m_doc, tag); +} + +KDE_NO_EXPORT bool DarkNode::expose () const { + return false; +} + +//----------------------------------------------------------------------------- + +GenericURL::GenericURL (NodePtr & d, const QString & s, const QString & name) + : Mrl (d, id_node_playlist_item) { + src = s; + if (!src.isEmpty ()) + setAttribute (StringPool::attr_src, src); + pretty_name = name; +} + +KDE_NO_EXPORT void GenericURL::closed () { + if (src.isEmpty ()) + src = getAttribute (StringPool::attr_src); +} + +//----------------------------------------------------------------------------- + +GenericMrl::GenericMrl (NodePtr & d, const QString & s, const QString & name, const QString & tag) + : Mrl (d, id_node_playlist_item), node_name (tag) { + src = s; + if (!src.isEmpty ()) + setAttribute (StringPool::attr_src, src); + pretty_name = name; + if (!name.isEmpty ()) + setAttribute (StringPool::attr_name, name); +} + +void GenericMrl::closed () { + if (src.isEmpty ()) { + src = getAttribute (StringPool::attr_src); + if (src.isEmpty ()) + src = getAttribute (StringPool::attr_url); + } + if (pretty_name.isEmpty ()) + pretty_name = getAttribute (StringPool::attr_name); +} + +bool GenericMrl::expose () const { + return !pretty_name.isEmpty () || //return false if no title and only one + previousSibling () || nextSibling (); +} + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + +class KMPLAYER_NO_EXPORT DocumentBuilder { + int m_ignore_depth; + bool m_set_opener; + bool m_root_is_first; + NodePtr m_node; + NodePtr m_root; +public: + DocumentBuilder (NodePtr d, bool set_opener); + ~DocumentBuilder () {} + bool startTag (const QString & tag, AttributeListPtr attr); + bool endTag (const QString & tag); + bool characterData (const QString & data); + bool cdataData (const QString & data); +#ifdef HAVE_EXPAT + void cdataStart (); + void cdataEnd (); +private: + bool in_cdata; + QString cdata; +#endif +}; + +} // namespace KMPlayer + +DocumentBuilder::DocumentBuilder (NodePtr d, bool set_opener) + : m_ignore_depth (0), m_set_opener (set_opener), m_root_is_first (false) + , m_node (d), m_root (d) +#ifdef HAVE_EXPAT + , in_cdata (false) +#endif +{} + +bool DocumentBuilder::startTag(const QString &tag, AttributeListPtr attr) { + if (m_ignore_depth) { + m_ignore_depth++; + //kdDebug () << "Warning: ignored tag " << tag.latin1 () << " ignore depth = " << m_ignore_depth << endl; + } else { + NodePtr n = m_node->childFromTag (tag); + if (!n) { + kdDebug () << "Warning: unknown tag " << tag.latin1 () << endl; + NodePtr doc = m_root->document (); + n = new DarkNode (doc, tag); + } + //kdDebug () << "Found tag " << tag << endl; + if (n->isElementNode ()) + convertNode <Element> (n)->setAttributes (attr); + if (m_node == n && m_node == m_root) + m_root_is_first = true; + else + m_node->appendChild (n); + if (m_set_opener && m_node == m_root) { + Mrl * mrl = n->mrl (); + if (mrl) + mrl->opener = m_root; + } + n->opened (); + m_node = n; + } + return true; +} + +bool DocumentBuilder::endTag (const QString & tag) { + if (m_ignore_depth) { // endtag to ignore + m_ignore_depth--; + kdDebug () << "Warning: ignored end tag " << " ignore depth = " << m_ignore_depth << endl; + } else { // endtag + NodePtr n = m_node; + while (n) { + if (!strcasecmp (n->nodeName (), tag.local8Bit ().data ()) && + (m_root_is_first || n != m_root)) { + while (n != m_node) { + kdWarning() << m_node->nodeName () << " not closed" << endl; + if (m_root == m_node->parentNode ()) + break; + m_node->closed (); + m_node = m_node->parentNode (); + } + break; + } + if (n == m_root) { + if (n == m_node) { + kdError () << "m_node == m_doc, stack underflow " << endl; + return false; + } + kdWarning () << "endtag: no match " << tag.local8Bit () << endl; + break; + } else + kdWarning () << "tag " << tag << " not " << n->nodeName () << endl; + n = n ->parentNode (); + } + //kdDebug () << "end tag " << tag << endl; + m_node->closed (); + m_node = m_node->parentNode (); + } + return true; +} + +bool DocumentBuilder::characterData (const QString & data) { + if (!m_ignore_depth) { +#ifdef HAVE_EXPAT + if (in_cdata) + cdata += data; + else +#endif + m_node->characterData (data); + } + //kdDebug () << "characterData " << d.latin1() << endl; + return true; +} + +bool DocumentBuilder::cdataData (const QString & data) { + if (!m_ignore_depth) { + NodePtr d = m_node->document (); + m_node->appendChild (new CData (d, data)); + } + //kdDebug () << "cdataData " << d.latin1() << endl; + return true; +} + +#ifdef HAVE_EXPAT + +void DocumentBuilder::cdataStart () { + cdata.truncate (0); + in_cdata = true; +} + +void DocumentBuilder::cdataEnd () { + cdataData (cdata); + cdata.truncate (0); + in_cdata = false; +} + +static void startTag (void *data, const char * tag, const char **attr) { + DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); + AttributeListPtr attributes = new AttributeList; + if (attr && attr [0]) { + for (int i = 0; attr[i]; i += 2) + attributes->append (new Attribute (QString::fromUtf8 (attr [i]), QString::fromUtf8 (attr [i+1]))); + } + builder->startTag (QString::fromUtf8 (tag), attributes); +} + +static void endTag (void *data, const char * tag) { + DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); + builder->endTag (QString::fromUtf8 (tag)); +} + +static void characterData (void *data, const char *s, int len) { + DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); + char * buf = new char [len + 1]; + strncpy (buf, s, len); + buf[len] = 0; + builder->characterData (QString::fromUtf8 (buf)); + delete [] buf; +} + +static void cdataStart (void *data) { + DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); + builder->cdataStart (); +} + +static void cdataEnd (void *data) { + DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); + builder->cdataEnd (); +} + +namespace KMPlayer { + +KMPLAYER_EXPORT +void readXML (NodePtr root, QTextStream & in, const QString & firstline, bool set_opener) { + bool ok = true; + DocumentBuilder builder (root, set_opener); + XML_Parser parser = XML_ParserCreate (0L); + XML_SetUserData (parser, &builder); + XML_SetElementHandler (parser, startTag, endTag); + XML_SetCharacterDataHandler (parser, characterData); + XML_SetCdataSectionHandler (parser, cdataStart, cdataEnd); + if (!firstline.isEmpty ()) { + QString str (firstline + QChar ('\n')); + QCString buf = str.utf8 (); + ok = XML_Parse(parser, buf, strlen (buf), false) != XML_STATUS_ERROR; + if (!ok) + kdWarning () << XML_ErrorString(XML_GetErrorCode(parser)) << " at " << XML_GetCurrentLineNumber(parser) << " col " << XML_GetCurrentColumnNumber(parser) << endl; + } + if (ok && !in.atEnd ()) { + QCString buf = in.read ().utf8 (); + ok = XML_Parse(parser, buf, strlen (buf), true) != XML_STATUS_ERROR; + if (!ok) + kdWarning () << XML_ErrorString(XML_GetErrorCode(parser)) << " at " << XML_GetCurrentLineNumber(parser) << " col " << XML_GetCurrentColumnNumber(parser) << endl; + } + XML_ParserFree(parser); + root->normalize (); + //return ok; +} + +} // namespace KMPlayer + +//----------------------------------------------------------------------------- +#else // HAVE_EXPAT + +namespace { + +class KMPLAYER_NO_EXPORT SimpleSAXParser { +public: + SimpleSAXParser (DocumentBuilder & b) : builder (b), position (0), m_attributes (new AttributeList), equal_seen (false), in_dbl_quote (false), in_sngl_quote (false), have_error (false), no_entitity_look_ahead (false), have_next_char (false) {} + virtual ~SimpleSAXParser () {}; + bool parse (QTextStream & d); +private: + QTextStream * data; + DocumentBuilder & builder; + int position; + QChar next_char; + enum Token { tok_empty, tok_text, tok_white_space, tok_angle_open, + tok_equal, tok_double_quote, tok_single_quote, tok_angle_close, + tok_slash, tok_exclamation, tok_amp, tok_hash, tok_semi_colon, + tok_question_mark, tok_cdata_start }; + enum State { + InTag, InStartTag, InPITag, InDTDTag, InEndTag, InAttributes, InContent, InCDATA, InComment + }; + struct TokenInfo { + TokenInfo () : token (tok_empty) {} + Token token; + QString string; + SharedPtr <TokenInfo> next; + }; + typedef SharedPtr <TokenInfo> TokenInfoPtr; + struct StateInfo { + StateInfo (State s, SharedPtr <StateInfo> n) : state (s), next (n) {} + State state; + QString data; + SharedPtr <StateInfo> next; + }; + SharedPtr <StateInfo> m_state; + TokenInfoPtr next_token, token, prev_token; + // for element reading + QString tagname; + AttributeListPtr m_attributes; + QString attr_name, attr_value; + QString cdata; + bool equal_seen; + bool in_dbl_quote; + bool in_sngl_quote; + bool have_error; + bool no_entitity_look_ahead; + bool have_next_char; + + bool readTag (); + bool readEndTag (); + bool readAttributes (); + bool readPI (); + bool readDTD (); + bool readCDATA (); + bool readComment (); + bool nextToken (); + void push (); + void push_attribute (); +}; + +} // namespace + +KMPLAYER_EXPORT +void KMPlayer::readXML (NodePtr root, QTextStream & in, const QString & firstline, bool set_opener) { + DocumentBuilder builder (root, set_opener); + SimpleSAXParser parser (builder); + if (!firstline.isEmpty ()) { + QString str (firstline + QChar ('\n')); + QTextStream fl_in (&str, IO_ReadOnly); + parser.parse (fl_in); + } + if (!in.atEnd ()) + parser.parse (in); + for (NodePtr e = root; e; e = e->parentNode ()) + e->closed (); + //doc->normalize (); + //kdDebug () << root->outerXML (); +} + +void SimpleSAXParser::push () { + if (next_token->string.length ()) { + prev_token = token; + token = next_token; + if (prev_token) + prev_token->next = token; + next_token = TokenInfoPtr (new TokenInfo); + //kdDebug () << "push " << token->string << endl; + } +} + +void SimpleSAXParser::push_attribute () { + //kdDebug () << "attribute " << attr_name.latin1 () << "=" << attr_value.latin1 () << endl; + m_attributes->append (new Attribute (attr_name, attr_value)); + attr_name.truncate (0); + attr_value.truncate (0); + equal_seen = in_sngl_quote = in_dbl_quote = false; +} + +bool SimpleSAXParser::nextToken () { + TokenInfoPtr cur_token = token; + while (!data->atEnd () && cur_token == token && !(token && token->next)) { + if (have_next_char) + have_next_char = false; + else + *data >> next_char; + bool append_char = true; + if (next_char.isSpace ()) { + if (next_token->token != tok_white_space) + push (); + next_token->token = tok_white_space; + } else if (!next_char.isLetterOrNumber ()) { + if (next_char == QChar ('#')) { + //if (next_token->token == tok_empty) { // check last item on stack & + push (); + next_token->token = tok_hash; + //} + } else if (next_char == QChar ('/')) { + push (); + next_token->token = tok_slash; + } else if (next_char == QChar ('!')) { + push (); + next_token->token = tok_exclamation; + } else if (next_char == QChar ('?')) { + push (); + next_token->token = tok_question_mark; + } else if (next_char == QChar ('<')) { + push (); + next_token->token = tok_angle_open; + } else if (next_char == QChar ('>')) { + push (); + next_token->token = tok_angle_close; + } else if (next_char == QChar (';')) { + push (); + next_token->token = tok_semi_colon; + } else if (next_char == QChar ('=')) { + push (); + next_token->token = tok_equal; + } else if (next_char == QChar ('"')) { + push (); + next_token->token = tok_double_quote; + } else if (next_char == QChar ('\'')) { + push (); + next_token->token = tok_single_quote; + } else if (next_char == QChar ('&')) { + push (); + if (no_entitity_look_ahead) { + have_next_char = true; + break; + } + append_char = false; + no_entitity_look_ahead = true; + TokenInfoPtr tmp = token; + TokenInfoPtr prev_tmp = prev_token; + if (nextToken () && token->token == tok_text && + nextToken () && token->token == tok_semi_colon) { + if (prev_token->string == QString ("amp")) + token->string = QChar ('&'); + else if (prev_token->string == QString ("lt")) + token->string = QChar ('<'); + else if (prev_token->string == QString ("gt")) + token->string = QChar ('>'); + else if (prev_token->string == QString ("quot")) + token->string = QChar ('"'); + else if (prev_token->string == QString ("apos")) + token->string = QChar ('\''); + else if (prev_token->string == QString ("copy")) + token->string = QChar (169); + else + token->string = QChar ('?');// TODO lookup more .. + token->token = tok_text; + if (tmp) { // cut out the & xxx ; tokens + tmp->next = token; + token = tmp; + } + //kdDebug () << "entity found "<<prev_token->string << endl; + } else if (token->token == tok_hash && + nextToken () && token->token == tok_text && + nextToken () && token->token == tok_semi_colon) { + //kdDebug () << "char entity found " << prev_token->string << prev_token->string.toInt (0L, 16) << endl; + token->token = tok_text; + if (!prev_token->string.startsWith (QChar ('x'))) + token->string = QChar (prev_token->string.toInt ()); + else + token->string = QChar (prev_token->string.mid (1).toInt (0L, 16)); + if (tmp) { // cut out the '& # xxx ;' tokens + tmp->next = token; + token = tmp; + } + } else { + token = tmp; // restore and insert the lost & token + tmp = TokenInfoPtr (new TokenInfo); + tmp->token = tok_amp; + tmp->string += QChar ('&'); + tmp->next = token->next; + if (token) + token->next = tmp; + else + token = tmp; // hmm + } + no_entitity_look_ahead = false; + prev_token = prev_tmp; + } else if (next_token->token != tok_text) { + push (); + next_token->token = tok_text; + } + } else if (next_token->token != tok_text) { + push (); + next_token->token = tok_text; + } + if (append_char) + next_token->string += next_char; + if (next_token->token == tok_text && + next_char == QChar ('[' ) && next_token->string == "[CDATA[") { + next_token->token = tok_cdata_start; + break; + } + } + if (token == cur_token) { + if (token && token->next) { + prev_token = token; + token = token->next; + } else if (next_token->string.length ()) { + push (); // last token + } else + return false; + return true; + } + return true; +} + +bool SimpleSAXParser::readAttributes () { + bool closed = false; + while (true) { + if (!nextToken ()) return false; + //kdDebug () << "readAttributes " << token->string.latin1() << endl; + if ((in_dbl_quote && token->token != tok_double_quote) || + (in_sngl_quote && token->token != tok_single_quote)) { + attr_value += token->string; + } else if (token->token == tok_equal) { + if (attr_name.isEmpty ()) + return false; + if (equal_seen) + attr_value += token->string; // EQ=a=2c ??? + //kdDebug () << "equal_seen"<< endl; + equal_seen = true; + } else if (token->token == tok_white_space) { + if (!attr_value.isEmpty ()) + push_attribute (); + } else if (token->token == tok_single_quote) { + if (!equal_seen) + attr_name += token->string; // D'OH=xxx ??? + else if (in_sngl_quote) { // found one + push_attribute (); + } else if (attr_value.isEmpty ()) + in_sngl_quote = true; + else + attr_value += token->string; + } else if (token->token == tok_double_quote) { + if (!equal_seen) + attr_name += token->string; // hmm + else if (in_dbl_quote) { // found one + push_attribute (); + } else if (attr_value.isEmpty ()) + in_dbl_quote = true; + else + attr_value += token->string; + //kdDebug () << "in_dbl_quote:"<< in_dbl_quote << endl; + } else if (token->token == tok_slash) { + TokenInfoPtr mark_token = token; + if (nextToken () && + (token->token != tok_white_space || nextToken()) &&//<e / > + token->token == tok_angle_close) { + //kdDebug () << "close mark:"<< endl; + closed = true; + break; + } else { + token = mark_token; + //kdDebug () << "not end mark:"<< equal_seen << endl; + if (equal_seen) + attr_value += token->string; // ABBR=w/o ??? + else + attr_name += token->string; + } + } else if (token->token == tok_angle_close) { + if (!attr_name.isEmpty ()) + push_attribute (); + break; + } else if (equal_seen) { + attr_value += token->string; + } else { + attr_name += token->string; + } + } + m_state = m_state->next; + if (m_state->state == InPITag) { + if (tagname == QString ("xml")) { + /*const AttributeMap::const_iterator e = attr.end (); + for (AttributeMap::const_iterator i = attr.begin (); i != e; ++i) + if (!strcasecmp (i.key ().latin1 (), "encoding")) + kdDebug () << "encodeing " << i.data().latin1() << endl;*/ + } + } else { + have_error = builder.startTag (tagname, m_attributes); + if (closed) + have_error &= builder.endTag (tagname); + //kdDebug () << "readTag " << tagname << " closed:" << closed << " ok:" << have_error << endl; + } + m_state = m_state->next; // pop Node or PI + return true; +} + +bool SimpleSAXParser::readPI () { + // TODO: <?xml .. encoding="ENC" .. ?> + if (!nextToken ()) return false; + if (token->token == tok_text && !token->string.compare ("xml")) { + m_state = new StateInfo (InAttributes, m_state); + return readAttributes (); + } else { + while (nextToken ()) + if (token->token == tok_angle_close) { + m_state = m_state->next; + return true; + } + } + return false; +} + +bool SimpleSAXParser::readDTD () { + //TODO: <!ENTITY ..> + if (!nextToken ()) return false; + if (token->token == tok_text && token->string.startsWith (QString ("--"))) { + m_state = new StateInfo (InComment, m_state->next); // note: pop DTD + return readComment (); + } + //kdDebug () << "readDTD: " << token->string.latin1 () << endl; + if (token->token == tok_cdata_start) { + m_state = new StateInfo (InCDATA, m_state->next); // note: pop DTD + if (token->next) { + cdata = token->next->string; + token->next = 0; + } else { + cdata = next_token->string; + next_token->string.truncate (0); + next_token->token = tok_empty; + } + return readCDATA (); + } + while (nextToken ()) + if (token->token == tok_angle_close) { + m_state = m_state->next; + return true; + } + return false; +} + +bool SimpleSAXParser::readCDATA () { + while (!data->atEnd ()) { + *data >> next_char; + if (next_char == QChar ('>') && cdata.endsWith (QString ("]]"))) { + cdata.truncate (cdata.length () - 2); + m_state = m_state->next; + if (m_state->state == InContent) + have_error = builder.cdataData (cdata); + else if (m_state->state == InAttributes) { + if (equal_seen) + attr_value += cdata; + else + attr_name += cdata; + } + cdata.truncate (0); + return true; + } + cdata += next_char; + } + return false; +} + +bool SimpleSAXParser::readComment () { + while (nextToken ()) { + if (token->token == tok_angle_close && prev_token) + if (prev_token->string.endsWith (QString ("--"))) { + m_state = m_state->next; + return true; + } + } + return false; +} + +bool SimpleSAXParser::readEndTag () { + if (!nextToken ()) return false; + if (token->token == tok_white_space) + if (!nextToken ()) return false; + tagname = token->string; + if (!nextToken ()) return false; + if (token->token == tok_white_space) + if (!nextToken ()) return false; + if (token->token != tok_angle_close) + return false; + have_error = builder.endTag (tagname); + m_state = m_state->next; + return true; +} + +// TODO: <!ENTITY ..> Ӓ +bool SimpleSAXParser::readTag () { + if (!nextToken ()) return false; + if (token->token == tok_exclamation) { + m_state = new StateInfo (InDTDTag, m_state->next); + //kdDebug () << "readTag: " << token->string.latin1 () << endl; + return readDTD (); + } + if (token->token == tok_white_space) + if (!nextToken ()) return false; // allow '< / foo', '< foo', '< ? foo' + if (token->token == tok_question_mark) { + m_state = new StateInfo (InPITag, m_state->next); + return readPI (); + } + if (token->token == tok_slash) { + m_state = new StateInfo (InEndTag, m_state->next); + return readEndTag (); + } + if (token->token != tok_text) + return false; // FIXME entities + tagname = token->string; + //kdDebug () << "readTag " << tagname.latin1() << endl; + m_state = new StateInfo (InAttributes, m_state); + return readAttributes (); +} + +bool SimpleSAXParser::parse (QTextStream & d) { + data = &d; + if (!next_token) { + next_token = TokenInfoPtr (new TokenInfo); + m_state = new StateInfo (InContent, m_state); + } + bool ok = true; + bool in_character_data = false; + QString white_space; + while (ok) { + switch (m_state->state) { + case InTag: + ok = readTag (); + break; + case InPITag: + ok = readPI (); + break; + case InDTDTag: + ok = readDTD (); + break; + case InEndTag: + ok = readEndTag (); + break; + case InAttributes: + ok = readAttributes (); + break; + case InCDATA: + ok = readCDATA (); + break; + case InComment: + ok = readComment (); + break; + default: + if ((ok = nextToken ())) { + if (token->token == tok_angle_open) { + attr_name.truncate (0); + attr_value.truncate (0); + m_attributes = new AttributeList; + equal_seen = in_sngl_quote = in_dbl_quote = false; + m_state = new StateInfo (InTag, m_state); + ok = readTag (); + in_character_data = false; + white_space.truncate (0); + } else if (token->token == tok_white_space) { + white_space += token->string; + } else { + if (!white_space.isEmpty ()) { + if (!in_character_data) { + int pos = white_space.findRev (QChar ('\n')); + if (pos > -1) + white_space = white_space.mid (pos + 1); + } + have_error = builder.characterData (white_space); + white_space.truncate (0); + } + have_error = builder.characterData (token->string); + in_character_data = true; + } + } + } + if (!m_state) + return true; // end document + } + return false; // need more data +} + +#endif // HAVE_EXPAT diff --git a/src/kmplayerplaylist.h b/src/kmplayerplaylist.h new file mode 100644 index 0000000..c9c0b6b --- /dev/null +++ b/src/kmplayerplaylist.h @@ -0,0 +1,979 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2004 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * until boost gets common, a more or less compatable one .. + */ + +#ifndef _KMPLAYER_PLAYLIST_H_ +#define _KMPLAYER_PLAYLIST_H_ + +#include <config.h> +#include <sys/time.h> + +#include <qstring.h> + +#include "kmplayer_def.h" +#include "kmplayertypes.h" +#include "kmplayershared.h" + +typedef struct _cairo_surface cairo_surface_t; + +class QTextStream; + +namespace KMPlayer { + +class Document; +class Node; +class Mrl; +class Surface; +class ElementPrivate; +class RemoteObjectPrivate; +class Visitor; + +/* + * Base class for objects that will be used as SharedPtr/WeakPtr pointers. + * Item<T> keeps its own copy of the shared SharedData<T> as a weak refence. + * \sa: self() + */ +template <class T> +class KMPLAYER_EXPORT Item { + friend class SharedPtr<T>; + friend class WeakPtr<T>; +public: + typedef SharedPtr <T> SharedType; + typedef WeakPtr <T> WeakType; + + virtual ~Item () {} + + SharedType self () const { return m_self; } +protected: + Item (); + WeakType m_self; +private: + Item (const Item <T> &); // forbidden copy constructor +}; + +/** + * Because of the m_self member of Item<T>, it's not allowed to assign a + * Item<T>* directly to SharedPtr<Item<T>>. Item<T>* will then reside in + * two independent SharedData<Item<T>> objects. + * So specialize constructor and assignment operators to fetch the + * SharedData<Item<T>> from the Item<T>* instead of creating a new one + */ +#define ITEM_AS_POINTER(CLASS) \ + template <> inline SharedPtr<CLASS>::SharedPtr (CLASS * t) \ + : data (t ? t->m_self.data : 0L) { \ + if (data) \ + data->addRef (); \ + } \ + \ + template <> \ + inline SharedPtr<CLASS> & SharedPtr<CLASS>::operator = (CLASS * t) { \ + if (t) { \ + operator = (t->m_self); \ + } else if (data) { \ + data->release (); \ + data = 0L; \ + } \ + return *this; \ + } \ + \ + template <> inline WeakPtr<CLASS>::WeakPtr (CLASS * t) \ + : data (t ? t->m_self.data : 0L) { \ + if (data) \ + data->addWeakRef (); \ + } \ + \ + template <> \ + inline WeakPtr<CLASS> & WeakPtr<CLASS>::operator = (CLASS * t) { \ + if (t) { \ + operator = (t->m_self); \ + } else if (data) { \ + data->releaseWeak (); \ + data = 0L; \ + } \ + return *this; \ + } + +/* + * A shareable double linked list of ListNodeBase<T> nodes + */ +template <class T> +class KMPLAYER_EXPORT List : public Item <List <T> > { +public: + List () {} + List (typename Item<T>::SharedType f, typename Item<T>::SharedType l) + : m_first (f), m_last (l) {} + ~List () { clear (); } + + typename Item<T>::SharedType first () const { return m_first; } + typename Item<T>::SharedType last () const { return m_last; } + void append (typename Item<T>::SharedType c); + void insertBefore(typename Item<T>::SharedType c, typename Item<T>::SharedType b); + void remove (typename Item<T>::SharedType c); + void clear (); + unsigned int length () const; + typename Item<T>::SharedType item (int i) const; +protected: + typename Item<T>::SharedType m_first; + typename Item<T>::WeakType m_last; +}; + +/* + * Base class for double linked list nodes of SharedPtr/WeakPtr objects. + * The linkage is a shared nextSibling and a weak previousSibling. + */ +template <class T> +class KMPLAYER_EXPORT ListNodeBase : public Item <T> { + friend class List<T>; +public: + virtual ~ListNodeBase () {} + + typename Item<T>::SharedType nextSibling () const { return m_next; } + typename Item<T>::SharedType previousSibling () const { return m_prev; } +protected: + ListNodeBase () {} + typename Item<T>::SharedType m_next; + typename Item<T>::WeakType m_prev; +}; + +/* + * ListNode for class T storage + */ +template <class T> +class ListNode : public ListNodeBase <ListNode <T> > { +public: + ListNode (T d) : data (d) {} + T data; +}; + +/* + * Base class for double linked tree nodes having parent/siblings/children. + * The linkage is a shared firstChild and weak parentNode. + */ +template <class T> +class KMPLAYER_EXPORT TreeNode : public ListNodeBase <T> { +public: + virtual ~TreeNode () {} + + virtual void appendChild (typename Item<T>::SharedType c); + virtual void removeChild (typename Item<T>::SharedType c); + + bool hasChildNodes () const { return m_first_child != 0L; } + typename Item<T>::SharedType parentNode () const { return m_parent; } + typename Item<T>::SharedType firstChild () const { return m_first_child; } + typename Item<T>::SharedType lastChild () const { return m_last_child; } + +protected: + TreeNode () {} + typename Item<T>::WeakType m_parent; + typename Item<T>::SharedType m_first_child; + typename Item<T>::WeakType m_last_child; +}; + +/** + * Attribute having a name/value pair for use with Elements + */ +class KMPLAYER_EXPORT Attribute : public ListNodeBase <Attribute> { +public: + KDE_NO_CDTOR_EXPORT Attribute () {} + Attribute (const TrieString & n, const QString & v); + KDE_NO_CDTOR_EXPORT ~Attribute () {} + TrieString name () const { return m_name; } + QString value () const { return m_value; } + void setName (const TrieString &); + void setValue (const QString &); +protected: + TrieString m_name; + QString m_value; +}; + +ITEM_AS_POINTER(KMPlayer::Attribute) + +/** + * Object should scale according the passed Fit value in SizedEvent + */ +enum Fit { + fit_fill, // fill complete area, no aspect preservation + fit_hidden, // keep aspect and don't scale, cut off what doesn't fit + fit_meet, // keep aspect and scale so that the smallest size just fits + fit_slice, // keep aspect and scale so that the largest size just fits + fit_scroll // keep aspect and don't scale, add scollbars if needed +}; + +/* + * A generic event type + */ +class KMPLAYER_EXPORT Event : public Item <Event> { +public: + KDE_NO_CDTOR_EXPORT Event (unsigned int event_id) : m_event_id (event_id) {} + KDE_NO_CDTOR_EXPORT virtual ~Event () {} + KDE_NO_EXPORT unsigned int id () const { return m_event_id; } +protected: + unsigned int m_event_id; +}; + +ITEM_AS_POINTER(KMPlayer::Event) + +extern const unsigned int event_pointer_clicked; +extern const unsigned int event_pointer_moved; +extern const unsigned int event_inbounds; +extern const unsigned int event_outbounds; +extern const unsigned int event_sized; +extern const unsigned int event_postponed; +extern const unsigned int event_timer; +extern const unsigned int mediatype_attached; + +// convenient types +typedef Item<Node>::SharedType NodePtr; +typedef Item<Node>::WeakType NodePtrW; +typedef Item<Attribute>::SharedType AttributePtr; +typedef Item<Attribute>::WeakType AttributePtrW; +typedef Item<Event>::SharedType EventPtr; +typedef List<Node> NodeList; // eg. for Node's children +typedef Item<NodeList>::SharedType NodeListPtr; +typedef Item<NodeList>::WeakType NodeListPtrW; +ITEM_AS_POINTER(KMPlayer::NodeList) +typedef List<Attribute> AttributeList; // eg. for Element's attributes +typedef Item<AttributeList>::SharedType AttributeListPtr; +ITEM_AS_POINTER(KMPlayer::AttributeList) +typedef ListNode<NodePtrW> NodeRefItem; // Node for ref Nodes +ITEM_AS_POINTER(KMPlayer::NodeRefItem) +//typedef ListNode<NodePtr> NodeStoreItem; // list stores Nodes +typedef NodeRefItem::SharedType NodeRefItemPtr; +typedef NodeRefItem::WeakType NodeRefItemPtrW; +typedef List<NodeRefItem> NodeRefList; // ref nodes, eg. event listeners +typedef Item<NodeRefList>::SharedType NodeRefListPtr; +typedef Item<NodeRefList>::WeakType NodeRefListPtrW; +ITEM_AS_POINTER(KMPlayer::NodeRefList) +typedef Item<Surface>::SharedType SurfacePtr; +typedef Item<Surface>::WeakType SurfacePtrW; + +/* + * Weak ref of the listeners list from signaler and the listener node + */ +class KMPLAYER_EXPORT Connection { + friend class Node; +public: + KDE_NO_CDTOR_EXPORT ~Connection () { disconnect (); } + void disconnect (); + NodePtrW connectee; // the one that will, when ever, trigger the event +private: + Connection (NodeRefListPtr ls, NodePtr node, NodePtr invoker); + NodeRefListPtrW listeners; + NodeRefItemPtrW listen_item; +}; + +typedef SharedPtr <Connection> ConnectionPtr; + +/* + * Base class for XML nodes. Provides a w3c's DOM like API + * + * Most severe traps with using SharedPtr/WeakPtr for tree nodes: + * - pointer ends up in two independent shared objects (hopefully with + * template specialization for constructor for T* and assignment of T* should + * be enough of defences ..) + * - Node added two times (added ASSERT in appendChild/insertBefore) + * - Node is destroyed before being stored in a SharedPtr with kmplayer usage + * of each object having a WeakPtr to itself (eg. be extremely careful with + * using m_self in the constructor, no SharedPtr storage yet) + * + * Livetime of an element is + |-->state_activated<-->state_began<-->state_finished-->state_deactivated-->| + In scope begin event end event Out scope + */ +class KMPLAYER_EXPORT Node : public TreeNode <Node> { + friend class DocumentBuilder; +public: + enum State { + state_init, state_deferred, + state_activated, state_began, state_finished, state_deactivated + }; + enum PlayType { + play_type_none, play_type_unknown, play_type_info, + play_type_image, play_type_audio, play_type_video + }; + virtual ~Node (); + Document * document (); + virtual Mrl * mrl (); + virtual NodePtr childFromTag (const QString & tag); + void characterData (const QString & s); + QString innerText () const; + QString innerXML () const; + QString outerXML () const; + virtual const char * nodeName () const; + virtual QString nodeValue () const; + virtual void setNodeName (const QString &) {} + + /** + * If this is a derived Mrl object and has a SRC attribute + */ + virtual PlayType playType (); + bool isPlayable () { return playType () > play_type_none; } + virtual bool isElementNode () { return false; } + /** + * If this node should be visible to the user + */ + virtual bool expose () const; + /** + * If this node should be visible to the user + */ + bool isEditable () const { return editable; } + /** + * If this node purpose is for storing runtime data only, + * ie. node doesn't exist in the original document + */ + bool auxiliaryNode () const { return auxiliary_node; } + void setAuxiliaryNode (bool b) { auxiliary_node = b; } + /** + * Add node as listener for a certain event_id. + * Return a NULL ptr if event_id is not supported. + * \sa: Connection::disconnect() + */ + ConnectionPtr connectTo (NodePtr node, unsigned int event_id); + /* + * Event send to this node, return true if handled + */ + virtual bool handleEvent (EventPtr event); + /* + * Dispatch Event to all listeners of event->id() + */ + void propagateEvent (EventPtr event); + /** + * Alternative to event handling is the Visitor pattern + */ + virtual void accept (Visitor *); + /* + * Returns a listener list for event_id, or a null ptr if not supported. + */ + virtual NodeRefListPtr listeners (unsigned int event_id); + /** + * Adds node to call 'handleEvent()' for all events that gets + * delivered to this node, ignored by default + */ + virtual SurfacePtr getSurface (NodePtr node); + /** + * Activates element, sets state to state_activated. Will call activate() on + * firstChild or call deactivate(). + */ + virtual void activate (); + /** + * if state is between state_activated and state_deactivated + */ + bool active () const + { return state >= state_deferred && state < state_deactivated; } + /** + * if state is between state_activated and state_finished + */ + bool unfinished () const + { return state > state_deferred && state < state_finished; } + /** + * Defers an activated, so possible playlists items can be added. + */ + virtual void defer (); + /** + * Puts a deferred element in activated again, calls activate() again + */ + virtual void undefer (); + /** + * Sets state to state_begin when active + */ + virtual void begin (); + /** + * Sets state to state_finish when >= state_activated. + * Notifies parent with a childDone call. + */ + virtual void finish (); + /** + * Stops element, sets state to state_deactivated. Calls deactivate() on + * activated/deferred children. May call childDone() when active() and not + * finished yet. + */ + virtual void deactivate (); + /** + * Resets element, calls deactivate() if state is state_activated and sets + * state to state_init. + */ + virtual void reset (); + /** + * Notification from child that it has began. + */ + virtual void childBegan (NodePtr child); + /** + * Notification from child that it's finished. Will call deactivate() on + * child if it state is state_finished. Call activate() on nexSibling + * or deactivate() if there is none. + */ + virtual void childDone (NodePtr child); + virtual void clear (); + void clearChildren (); + void appendChild (NodePtr c); + void insertBefore (NodePtr c, NodePtr b); + void removeChild (NodePtr c); + void replaceChild (NodePtr _new, NodePtr old); + /* + * Get rid of whitespace only text nodes + */ + void normalize (); + KDE_NO_EXPORT bool isDocument () const { return m_doc == m_self; } + + KDE_NO_EXPORT NodeListPtr childNodes () const; + void setState (State nstate); + /* + * Open tag is found by parser, attributes are set + */ + virtual void opened (); + /* + * Close tag is found by parser, children are appended + */ + virtual void closed (); +protected: + Node (NodePtr & d, short _id=0); + NodePtr m_doc; +public: + State state; + short id; +private: + bool auxiliary_node; +protected: + bool editable; +}; + +ITEM_AS_POINTER(KMPlayer::Node) + +const short id_node_document = 1; +const short id_node_text = 5; +const short id_node_cdata = 6; + +const short id_node_group_node = 25; +const short id_node_playlist_document = 26; +const short id_node_playlist_item = 27; +const short id_node_param = 28; +const short id_node_html_object = 29; +const short id_node_html_embed = 30; + +/* + * Element node, XML node that can have attributes + */ +class KMPLAYER_EXPORT Element : public Node { +public: + ~Element (); + void setAttributes (AttributeListPtr attrs); + void setAttribute (const TrieString & name, const QString & value); + QString getAttribute (const TrieString & name); + KDE_NO_EXPORT AttributeListPtr attributes () const { return m_attributes; } + virtual void init (); + virtual void reset (); + virtual void clear (); + virtual bool isElementNode () { return true; } + /** + * Params are like attributes, but meant to be set dynamically. Caller may + * pass a modification id, that it can use to restore the old value. + * Param will be auto removed on deactivate + */ + void setParam (const TrieString ¶, const QString &val, int * mod_id=0L); + QString param (const TrieString & para); + void resetParam (const TrieString & para, int mod_id); + /** + * Called from (re)setParam for specialized interpretation of params + **/ + virtual void parseParam (const TrieString &, const QString &) {} +protected: + Element (NodePtr & d, short id=0); + AttributeListPtr m_attributes; +private: + ElementPrivate * d; +}; + +/** + * Node that references another node + */ +class RefNode : public Node { +public: + RefNode (NodePtr & d, NodePtr ref); + virtual const char * nodeName () const { return tag_name.ascii (); } + NodePtr refNode () const { return ref_node; } + void setRefNode (const NodePtr ref); +protected: + NodePtrW ref_node; + QString tag_name; +}; + +template <class T> +inline KDE_NO_EXPORT T * convertNode (NodePtr e) { + return static_cast <T *> (e.ptr ()); +} + +/** + * Element representing a playable link, like URL to a movie or playlist. + */ +class KMPLAYER_EXPORT Mrl : public Element { +protected: + Mrl (NodePtr & d, short id=0); + NodePtr childFromTag (const QString & tag); + void parseParam (const TrieString &, const QString &); + unsigned int cached_ismrl_version; + PlayType cached_play_type; +public: + ~Mrl (); + PlayType playType (); + /* + * The original node (or this) having the URL, needed for playlist expansion + */ + virtual Mrl * linkNode (); + virtual Mrl * mrl (); + virtual void endOfFile (); + QString absolutePath (); + /* + * Reimplement to callback with requestPlayURL if isPlayable() + */ + virtual void activate (); + virtual void begin (); + /** + * By default support one event handler (eg. SMIL or RP child document) + */ + virtual SurfacePtr getSurface (NodePtr node); + virtual bool handleEvent (EventPtr event); + + /** + * If this Mrl is top node of external document, opener has the + * location in SCR. Typically that's the parent of this node. + */ + NodePtrW opener; //if this node is top node of external document, + QString src; + QString pretty_name; + QString mimetype; + Single width; + Single height; + float aspect; + int repeat; + enum { SingleMode = 0, WindowMode } view_mode; + bool resolved; + bool bookmarkable; +}; + +/** + * Document listener interface + */ +class KMPLAYER_EXPORT PlayListNotify { +public: + virtual ~PlayListNotify () {} + /** + * Ask for playing a video/audio mrl by backend players + * If returning false, the element will be set to finished + */ + virtual bool requestPlayURL (NodePtr mrl) = 0; + /** + * Called by an unresolved Mrl, check if this node points to a playlist + */ + virtual bool resolveURL (NodePtr mrl) = 0; + /** + * Element has activated or deactivated notification + */ + virtual void stateElementChanged (Node * element, Node::State old_state, Node::State new_state) = 0; + /** + * Set element to which to send GUI events and return a surface for drawing + */ + virtual SurfacePtr getSurface (NodePtr node) = 0; + /** + * Request to show msg for informing the user + */ + virtual void setInfoMessage (const QString & msg) = 0; + /** + * Ask for connection bitrates settings + */ + virtual void bitRates (int & preferred, int & maximal) = 0; + /** + * Sets next call to Document::timer() or -1 to cancel a previous call + */ + virtual void setTimeout (int ms) = 0; +}; + +/** + * Base class for cached network data + */ +class KMPLAYER_NO_EXPORT RemoteObject { + friend class RemoteObjectPrivate; +public: + RemoteObject (); + virtual ~RemoteObject (); + bool wget (const QString & url); + void killWGet (); + void clear (); + QString mimetype (); +protected: + KDE_NO_EXPORT virtual void remoteReady (QByteArray &) {} + bool downloading () const; +private: + RemoteObjectPrivate *d; +}; + +class KMPLAYER_NO_EXPORT Surface : public TreeNode <Surface> { +public: + Surface (NodePtr node, const SRect & rect); + ~Surface(); + + virtual SurfacePtr createSurface (NodePtr owner, const SRect & rect) = 0; + virtual IRect toScreen (Single x, Single y, Single w, Single h) = 0; + virtual void resize (const SRect & rect) = 0; + virtual void repaint () = 0; + virtual void repaint (const SRect &rect) = 0; + virtual void video () = 0; + void remove (); // remove from parent, mark ancestors dirty + void markDirty (); // mark this and ancestors dirty + + NodePtrW node; + SRect bounds; // bounds in in parent coord. + float xscale, yscale; // internal scaling + unsigned int background_color; // rgba background color + bool dirty; // a decendant is removed +#ifdef HAVE_CAIRO + cairo_surface_t *surface; +#endif +}; + +ITEM_AS_POINTER(KMPlayer::Surface) + +/** + * To have a somewhat synchronized time base, node having timers should use + * this. Idea is that if a node still waiting for network data, it can hold + * this time line. + */ +class KMPLAYER_NO_EXPORT TimerInfo : public ListNodeBase <TimerInfo> { +public: + TimerInfo (NodePtr n, unsigned id, struct timeval & now, int ms); + KDE_NO_CDTOR_EXPORT ~TimerInfo () {} + NodePtrW node; + unsigned event_id; + struct timeval timeout; + int milli_sec; +}; + +ITEM_AS_POINTER(KMPlayer::TimerInfo) +typedef Item <TimerInfo>::SharedType TimerInfoPtr; +typedef Item <TimerInfo>::WeakType TimerInfoPtrW; + +/** + * Event signaling a timer event + */ +class KMPLAYER_NO_EXPORT TimerEvent : public Event { +public: + TimerEvent (TimerInfoPtr tinfo); + TimerInfoPtrW timer_info; + bool interval; // set to 'true' in 'Node::handleEvent()' to make it repeat +}; + +/** + * Event signaling postponed or proceeded + */ +class KMPLAYER_NO_EXPORT PostponedEvent : public Event { +public: + PostponedEvent (bool postponed); + bool is_postponed; // postponed or proceeded +}; + +/** + * Postpone object representing a postponed document + * During its livetime, no TimerEvent's happen + */ +class KMPLAYER_NO_EXPORT Postpone { + friend class Document; + struct timeval postponed_time; + NodePtrW m_doc; + Postpone (NodePtr doc); +public: + ~Postpone (); +}; + +typedef SharedPtr <Postpone> PostponePtr; +typedef WeakPtr <Postpone> PostponePtrW; + +/** + * The root of the DOM tree + */ +class KMPLAYER_EXPORT Document : public Mrl { + friend class Postpone; +public: + Document (const QString &, PlayListNotify * notify = 0L); + ~Document (); + NodePtr getElementById (const QString & id); + NodePtr getElementById (NodePtr start, const QString & id, bool inter_doc); + /** All nodes have shared pointers to Document, + * so explicitly dispose it (calls clear and set m_doc to 0L) + * */ + void dispose (); + virtual NodePtr childFromTag (const QString & tag); + KDE_NO_EXPORT const char * nodeName () const { return "document"; } + virtual void activate (); + virtual void defer (); + virtual void undefer (); + virtual void reset (); + /** + * Ask for TimerEvent for Node n in ms milli-seconds. + * Returns weak ref to TimerInfo ptr, which is an item in the timers list + */ + TimerInfoPtrW setTimeout (NodePtr n, int ms, unsigned id=0); + void cancelTimer (TimerInfoPtr ti); + void timeOfDay (struct timeval &); + PostponePtr postpone (); + /** + * Called by PlayListNotify, creates TimerEvent on first item in timers. + * Returns true if to repeat this same timeout FIXME. + */ + bool timer (); + /** + * Document has list of postponed listeners, eg. for running (gif)movies + */ + virtual NodeRefListPtr listeners (unsigned int event_id); + /** + * Reimplement, so it will call PlayListNotify::getSurface() + */ + virtual SurfacePtr getSurface (NodePtr node); + + List <TimerInfo> timers; //FIXME: make as connections + PlayListNotify * notify_listener; + unsigned int m_tree_version; + unsigned int last_event_time; +private: + void proceed (const struct timeval & postponed_time); + PostponePtrW postpone_ref; + PostponePtr postpone_lock; + NodeRefListPtr m_PostponedListeners; + int cur_timeout; + struct timeval first_event_time; + bool intimer; +}; + +/** + * Represents XML text, like "some text" in '<foo>some text</foo>' + */ +class KMPLAYER_EXPORT TextNode : public Node { +public: + TextNode (NodePtr & d, const QString & s, short _id = id_node_text); + KDE_NO_CDTOR_EXPORT ~TextNode () {} + void appendText (const QString & s); + void setText (const QString & txt) { text = txt; } + const char * nodeName () const { return "#text"; } + QString nodeValue () const; + bool expose () const; +protected: + QString text; +}; + +/** + * Represents cdata sections, like "some text" in '<![CDATA[some text]]>' + */ +class KMPLAYER_EXPORT CData : public TextNode { +public: + CData (NodePtr & d, const QString & s); + KDE_NO_CDTOR_EXPORT ~CData () {} + const char * nodeName () const { return "#cdata"; } +}; + +/** + * Unrecognized tag by parent element or just some auxiliary node + */ +class KMPLAYER_EXPORT DarkNode : public Element { +public: + DarkNode (NodePtr & d, const QString & n, short id=0); + KDE_NO_CDTOR_EXPORT ~DarkNode () {} + const char * nodeName () const { return name.ascii (); } + NodePtr childFromTag (const QString & tag); + virtual bool expose () const; +protected: + QString name; +}; + +namespace SMIL { + class RegionBase; + class Region; + class Layout; + class Transition; + class MediaType; + class ImageMediaType; + class TextMediaType; + class RefMediaType; + class AVMediaType; + class Brush; + class TimedMrl; + class Anchor; + class Area; +} +namespace RP { + class Imfl; + class Crossfade; + class Fadein; + class Fadeout; + class Fill; + class Wipe; + class ViewChange; + class Animate; +} + +class KMPLAYER_NO_EXPORT Visitor { +public: + KDE_NO_CDTOR_EXPORT Visitor () {} + KDE_NO_CDTOR_EXPORT virtual ~Visitor () {} + virtual void visit (Node *) {} + virtual void visit (SMIL::Region *); + virtual void visit (SMIL::Layout *); + virtual void visit (SMIL::Transition *); + virtual void visit (SMIL::TimedMrl *); + virtual void visit (SMIL::MediaType *); + virtual void visit (SMIL::ImageMediaType *); + virtual void visit (SMIL::TextMediaType *); + virtual void visit (SMIL::RefMediaType *); + virtual void visit (SMIL::AVMediaType *); + virtual void visit (SMIL::Brush *); + virtual void visit (SMIL::Anchor *); + virtual void visit (SMIL::Area *); + virtual void visit (RP::Imfl *) {} + virtual void visit (RP::Crossfade *) {} + virtual void visit (RP::Fadein *) {} + virtual void visit (RP::Fadeout *) {} + virtual void visit (RP::Fill *) {} + virtual void visit (RP::Wipe *) {} + virtual void visit (RP::ViewChange *) {} + virtual void visit (RP::Animate *) {} +}; + +//----------------------------------------------------------------------------- + +/** + * just some url, can get a SMIL, RSS, or ASX childtree + */ +class KMPLAYER_EXPORT GenericURL : public Mrl { +public: + GenericURL(NodePtr &d, const QString &s, const QString &n=QString ()); + KDE_NO_EXPORT const char * nodeName () const { return "url"; } + void closed (); +}; + +/** + * Non url mrl + */ +class KMPLAYER_EXPORT GenericMrl : public Mrl { +public: + KDE_NO_CDTOR_EXPORT GenericMrl (NodePtr & d) : Mrl (d), node_name ("mrl") {} + GenericMrl(NodePtr &d, const QString &s, const QString & name=QString (), const QString &tag=QString ("mrl")); + KDE_NO_EXPORT const char * nodeName () const { return node_name.ascii (); } + void closed (); + bool expose () const; + QString node_name; +}; + +KMPLAYER_EXPORT +void readXML (NodePtr root, QTextStream & in, const QString & firstline, bool set_opener=true); +KMPLAYER_EXPORT Node * fromXMLDocumentTag (NodePtr & d, const QString & tag); + +template <class T> +inline Item<T>::Item () : m_self (static_cast <T*> (this), true) {} + +template <class T> inline void List<T>::append(typename Item<T>::SharedType c) { + if (!m_first) { + m_first = m_last = c; + } else { + m_last->m_next = c; + c->m_prev = m_last; + m_last = c; + } +} + +template <class T> inline void List<T>::insertBefore(typename Item<T>::SharedType c, typename Item<T>::SharedType b) { + if (!b) { + append (c); + } else { + if (b->m_prev) { + b->m_prev->m_next = c; + c->m_prev = b->m_prev; + } else { + c->m_prev = 0L; + m_first = c; + } + b->m_prev = c; + c->m_next = b; + } +} + +template <class T> inline void List<T>::remove(typename Item<T>::SharedType c) { + if (c->m_prev) { + c->m_prev->m_next = c->m_next; + } else + m_first = c->m_next; + if (c->m_next) { + c->m_next->m_prev = c->m_prev; + c->m_next = 0L; + } else + m_last = c->m_prev; + c->m_prev = 0L; +} + +template <class T> inline unsigned int List<T>::length () const { + unsigned int count = 0; + for (typename Item<T>::SharedType t = m_first; t; t = t->nextSibling ()) + count++; + return count; +} + +template <class T> inline void List<T>::clear () { + m_first = m_last = 0L; +} + +template <class T> +inline typename Item<T>::SharedType List<T>::item (int i) const { + for (typename Item<T>::SharedType t = m_first; t; t = t->nextSibling(), --i) + if (i == 0) + return t; + return typename Item<T>::SharedType (); +} + +template <class T> +inline void TreeNode<T>::appendChild (typename Item<T>::SharedType c) { + if (!m_first_child) { + m_first_child = m_last_child = c; + } else { + m_last_child->m_next = c; + c->m_prev = m_last_child; + m_last_child = c; + } + c->m_parent = Item<T>::m_self; +} + +template <class T> +inline void TreeNode<T>::removeChild (typename Item<T>::SharedType c) { + if (c->m_prev) { + c->m_prev->m_next = c->m_next; + } else + m_first_child = c->m_next; + if (c->m_next) { + c->m_next->m_prev = c->m_prev; + c->m_next = 0L; + } else + m_last_child = c->m_prev; + c->m_prev = 0L; + c->m_parent = 0L; +} + +inline KDE_NO_EXPORT NodeListPtr Node::childNodes () const { + return new NodeList (m_first_child, m_last_child); +} + +} // KMPlayer namespace + +#endif //_KMPLAYER_PLAYLIST_H_ diff --git a/src/kmplayerprocess.cpp b/src/kmplayerprocess.cpp new file mode 100644 index 0000000..fff98f4 --- /dev/null +++ b/src/kmplayerprocess.cpp @@ -0,0 +1,2567 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2003 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include <math.h> +#include <config.h> +#include <qstring.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qtimer.h> +#include <qlayout.h> +#include <qtable.h> +#include <qlineedit.h> +#include <qslider.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qfontmetrics.h> +#include <qwhatsthis.h> + +#include <dcopobject.h> +#include <dcopclient.h> +#include <kprocess.h> +#include <kdebug.h> +#include <kprocctrl.h> +#include <kprotocolmanager.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kapplication.h> +#include <kstandarddirs.h> +#include <kio/job.h> + +#ifdef HAVE_DBUS +# include <kstaticdeleter.h> +# include <dbus/connection.h> +#endif + +#include "kmplayerview.h" +#include "kmplayercontrolpanel.h" +#include "kmplayerprocess.h" +#include "kmplayersource.h" +#include "kmplayerconfig.h" +#include "kmplayer_callback.h" +#include "kmplayer_backend_stub.h" + +using namespace KMPlayer; + +static const char * default_supported [] = { 0L }; + +static QString getPath (const KURL & url) { + QString p = KURL::decode_string (url.url ()); + if (p.startsWith (QString ("file:/"))) { + p = p.mid (5); + unsigned int i = 0; + for (; i < p.length () && p[i] == QChar ('/'); ++i) + ; + //kdDebug () << "getPath " << p.mid (i-1) << endl; + if (i > 0) + return p.mid (i-1); + return QString (QChar ('/') + p); + } + return p; +} + +Process::Process (QObject * parent, Settings * settings, const char * n) + : QObject (parent, n), m_source (0L), m_settings (settings), + m_state (NotRunning), m_old_state (NotRunning), m_process (0L), m_job(0L), + m_supported_sources (default_supported), m_viewer (0L) {} + +Process::~Process () { + stop (); + delete m_process; +} + +void Process::init () { +} + +QString Process::menuName () const { + return QString (className ()); +} + +void Process::initProcess (Viewer * viewer) { + m_viewer = viewer; + delete m_process; + m_process = new KProcess; + m_process->setUseShell (true); + m_process->setEnvironment (QString::fromLatin1 ("SESSION_MANAGER"), QString::fromLatin1 ("")); + if (m_source) m_source->setPosition (0); +} + +WId Process::widget () { + return 0; +} + +bool Process::playing () const { + return m_process && m_process->isRunning (); +} + +void Process::setAudioLang (int, const QString &) {} + +void Process::setSubtitle (int, const QString &) {} + +bool Process::pause () { + return false; +} + +bool Process::seek (int /*pos*/, bool /*absolute*/) { + return false; +} + +bool Process::volume (int /*pos*/, bool /*absolute*/) { + return false; +} + +bool Process::saturation (int /*pos*/, bool /*absolute*/) { + return false; +} + +bool Process::hue (int /*pos*/, bool /*absolute*/) { + return false; +} + +bool Process::contrast (int /*pos*/, bool /*absolute*/) { + return false; +} + +bool Process::brightness (int /*pos*/, bool /*absolute*/) { + return false; +} + +bool Process::grabPicture (const KURL & /*url*/, int /*pos*/) { + return false; +} + +bool Process::supports (const char * source) const { + for (const char ** s = m_supported_sources; s[0]; ++s) { + if (!strcmp (s[0], source)) + return true; + } + return false; +} + +bool Process::stop () { + if (!playing ()) + return true; + return false; +} + +bool Process::quit () { + while (playing ()) { + if (m_source && !m_source->pipeCmd ().isEmpty ()) { + void (*oldhandler)(int) = signal(SIGTERM, SIG_IGN); + ::kill (-1 * ::getpid (), SIGTERM); + signal(SIGTERM, oldhandler); + } else + m_process->kill (SIGTERM); + KProcessController::theKProcessController->waitForProcessExit (1); + if (!m_process->isRunning ()) + break; + m_process->kill (SIGKILL); + KProcessController::theKProcessController->waitForProcessExit (1); + if (m_process->isRunning ()) { + KMessageBox::error (viewer (), i18n ("Failed to end player process."), i18n ("Error")); + } + break; + } + setState (NotRunning); + return !playing (); +} + +void Process::setState (State newstate) { + if (m_state != newstate) { + bool need_timer = m_old_state == m_state; + m_old_state = m_state; + m_state = newstate; + if (need_timer && m_source) + QTimer::singleShot (0, this, SLOT (rescheduledStateChanged ())); + } +} + +KDE_NO_EXPORT void Process::rescheduledStateChanged () { + State old_state = m_old_state; + m_old_state = m_state; + m_source->stateChange (this, old_state, m_state); +} + +bool Process::play (Source * src, NodePtr _mrl) { + m_source = src; + m_mrl = _mrl; + Mrl * m = _mrl ? _mrl->mrl () : 0L; + QString url = m ? m->absolutePath () : QString (); + bool changed = m_url != url; + m_url = url; +#if KDE_IS_VERSION(3,3,91) + if (!changed || KURL (m_url).isLocalFile ()) + return deMediafiedPlay (); + m_url = url; + m_job = KIO::stat (m_url, false); + connect(m_job, SIGNAL (result(KIO::Job *)), this, SLOT(result(KIO::Job *))); + return true; +#else + return deMediafiedPlay (); +#endif +} + +bool Process::deMediafiedPlay () { + return false; +} + +void Process::result (KIO::Job * job) { +#if KDE_IS_VERSION(3,3,91) + KIO::UDSEntry entry = static_cast <KIO::StatJob *> (job)->statResult (); + KIO::UDSEntry::iterator e = entry.end (); + for (KIO::UDSEntry::iterator it = entry.begin (); it != e; ++it) + if ((*it).m_uds == KIO::UDS_LOCAL_PATH) { + m_url = KURL::fromPathOrURL ((*it).m_str).url (); + break; + } + m_job = 0L; + deMediafiedPlay (); +#endif +} + +void Process::terminateJobs () { + if (m_job) { + m_job->kill (); + m_job = 0L; + } +} + +bool Process::ready (Viewer * viewer) { + m_viewer = viewer; + setState (Ready); + return true; +} + +Viewer * Process::viewer () const { + return (m_viewer ? (Viewer*)m_viewer : + (m_settings->defaultView() ? m_settings->defaultView()->viewer() : 0L)); +} + +//----------------------------------------------------------------------------- + +static bool proxyForURL (const KURL& url, QString& proxy) { + KProtocolManager::slaveProtocol (url, proxy); + return !proxy.isNull (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT MPlayerBase::MPlayerBase (QObject * parent, Settings * settings, const char * n) + : Process (parent, settings, n), m_use_slave (true) { + m_process = new KProcess; +} + +KDE_NO_CDTOR_EXPORT MPlayerBase::~MPlayerBase () { +} + +KDE_NO_EXPORT void MPlayerBase::initProcess (Viewer * viewer) { + Process::initProcess (viewer); + const KURL & url (m_source->url ()); + if (!url.isEmpty ()) { + QString proxy_url; + if (KProtocolManager::useProxy () && proxyForURL (url, proxy_url)) + m_process->setEnvironment("http_proxy", proxy_url); + } + connect (m_process, SIGNAL (wroteStdin (KProcess *)), + this, SLOT (dataWritten (KProcess *))); + connect (m_process, SIGNAL (processExited (KProcess *)), + this, SLOT (processStopped (KProcess *))); +} + +KDE_NO_EXPORT bool MPlayerBase::sendCommand (const QString & cmd) { + if (playing () && m_use_slave) { + commands.push_front (cmd + '\n'); + fprintf (stderr, "eval %s", commands.last ().latin1 ()); + if (commands.size () < 2) + m_process->writeStdin (QFile::encodeName(commands.last ()), + commands.last ().length ()); + return true; + } + return false; +} + +KDE_NO_EXPORT bool MPlayerBase::stop () { + terminateJobs (); + if (!m_source || !m_process || !m_process->isRunning ()) + return true; + return true; +} + +KDE_NO_EXPORT bool MPlayerBase::quit () { + if (playing ()) { + stop (); + disconnect (m_process, SIGNAL (processExited (KProcess *)), + this, SLOT (processStopped (KProcess *))); + if (!m_use_slave) { + void (*oldhandler)(int) = signal(SIGTERM, SIG_IGN); + ::kill (-1 * ::getpid (), SIGTERM); + signal(SIGTERM, oldhandler); + } +#if KDE_IS_VERSION(3, 1, 90) + m_process->wait(2); +#else + QTime t; + t.start (); + do { + KProcessController::theKProcessController->waitForProcessExit (2); + } while (t.elapsed () < 2000 && m_process->isRunning ()); +#endif + if (m_process->isRunning ()) + Process::quit (); + processStopped (0L); + commands.clear (); + } + return Process::quit (); +} + +KDE_NO_EXPORT void MPlayerBase::dataWritten (KProcess *) { + if (!commands.size ()) return; + kdDebug() << "eval done " << commands.last () << endl; + commands.pop_back (); + if (commands.size ()) + m_process->writeStdin (QFile::encodeName(commands.last ()), + commands.last ().length ()); +} + +KDE_NO_EXPORT void MPlayerBase::processStopped (KProcess *) { + kdDebug() << "process stopped" << endl; + commands.clear (); + setState (Ready); +} + +//----------------------------------------------------------------------------- + +static const char * mplayer_supports [] = { + "dvdsource", "exitsource", "hrefsource", "introsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L +}; + +KDE_NO_CDTOR_EXPORT MPlayer::MPlayer (QObject * parent, Settings * settings) + : MPlayerBase (parent, settings, "mplayer"), + m_widget (0L), + m_configpage (new MPlayerPreferencesPage (this)), + aid (-1), sid (-1), + m_needs_restarted (false) { + m_supported_sources = mplayer_supports; + m_settings->addPage (m_configpage); +} + +KDE_NO_CDTOR_EXPORT MPlayer::~MPlayer () { + if (m_widget && !m_widget->parent ()) + delete m_widget; + delete m_configpage; +} + +KDE_NO_EXPORT void MPlayer::init () { +} + +QString MPlayer::menuName () const { + return i18n ("&MPlayer"); +} + +KDE_NO_EXPORT WId MPlayer::widget () { + return viewer ()->embeddedWinId (); +} + +KDE_NO_EXPORT bool MPlayer::ready (Viewer * viewer) { + Process::ready (viewer); + viewer->changeProtocol (QXEmbed::XPLAIN); + return false; +} + +KDE_NO_EXPORT bool MPlayer::deMediafiedPlay () { + if (playing ()) + return sendCommand (QString ("gui_play")); + if (!m_needs_restarted && playing ()) + quit (); // rescheduling of setState will reset state just-in-time + initProcess (viewer ()); + m_source->setPosition (0); + if (!m_needs_restarted) { + aid = sid = -1; + } else + m_needs_restarted = false; + alanglist = 0L; + slanglist = 0L; + m_request_seek = -1; + QString args = m_source->options () + ' '; + KURL url (m_url); + if (!url.isEmpty ()) { + if (m_source->url ().isLocalFile ()) + m_process->setWorkingDirectory + (QFileInfo (m_source->url ().path ()).dirPath (true)); + if (url.isLocalFile ()) { + m_url = getPath (url); + if (m_configpage->alwaysbuildindex && + (m_url.lower ().endsWith (".avi") || + m_url.lower ().endsWith (".divx"))) + args += QString (" -idx "); + } else { + int cache = m_configpage->cachesize; + if (cache > 3 && !url.url ().startsWith (QString ("dvd")) && + !url.url ().startsWith (QString ("vcd")) && + !url.url ().startsWith (QString ("tv://"))) + args += QString ("-cache %1 ").arg (cache); + if (m_url.startsWith (QString ("cdda:/")) && + !m_url.startsWith (QString ("cdda://"))) + m_url = QString ("cdda://") + m_url.mid (6); + } + if (url.protocol () != QString ("stdin")) + args += KProcess::quote (QString (QFile::encodeName (m_url))); + } + m_tmpURL.truncate (0); + if (!m_source->identified () && !m_settings->mplayerpost090) { + args += QString (" -quiet -nocache -identify -frames 0 "); + } else { + if (m_mrl->mrl ()->repeat > 0) + args += QString(" -loop " +QString::number(m_mrl->mrl()->repeat+1)); + else if (m_settings->loop) + args += QString (" -loop 0"); + if (m_settings->mplayerpost090) + args += QString (" -identify"); + if (!m_source->subUrl ().isEmpty ()) { + args += QString (" -sub "); + const KURL & sub_url (m_source->subUrl ()); + if (!sub_url.isEmpty ()) { + QString myurl (sub_url.isLocalFile () ? getPath (sub_url) : sub_url.url ()); + args += KProcess::quote (QString (QFile::encodeName (myurl))); + } + } + } + return run (args.ascii (), m_source->pipeCmd ().ascii ()); +} + +KDE_NO_EXPORT bool MPlayer::stop () { + terminateJobs (); + if (!m_source || !m_process || !m_process->isRunning ()) return true; + if (m_use_slave) + sendCommand (QString ("quit")); + return MPlayerBase::stop (); +} + +KDE_NO_EXPORT bool MPlayer::pause () { + return sendCommand (QString ("pause")); +} + +KDE_NO_EXPORT bool MPlayer::seek (int pos, bool absolute) { + if (!m_source || !m_source->hasLength () || + (absolute && m_source->position () == pos)) + return false; + if (m_request_seek >= 0 && commands.size () > 1) { + QStringList::iterator i = commands.begin (); + QStringList::iterator end ( commands.end () ); + for (++i; i != end; ++i) + if ((*i).startsWith (QString ("seek"))) { + i = commands.erase (i); + m_request_seek = -1; + break; + } + } + if (m_request_seek >= 0) { + //m_request_seek = pos; + return false; + } + m_request_seek = pos; + QString cmd; + cmd.sprintf ("seek %d %d", pos/10, absolute ? 2 : 0); + if (!absolute) + pos = m_source->position () + pos; + m_source->setPosition (pos); + return sendCommand (cmd); +} + +KDE_NO_EXPORT bool MPlayer::volume (int incdec, bool absolute) { + if (absolute) + incdec -= old_volume; + if (incdec == 0) + return true; + old_volume += incdec; + return sendCommand (QString ("volume ") + QString::number (incdec)); +} + +KDE_NO_EXPORT bool MPlayer::saturation (int val, bool absolute) { + QString cmd; + cmd.sprintf ("saturation %d %d", val, absolute ? 1 : 0); + return sendCommand (cmd); +} + +KDE_NO_EXPORT bool MPlayer::hue (int val, bool absolute) { + QString cmd; + cmd.sprintf ("hue %d %d", val, absolute ? 1 : 0); + return sendCommand (cmd); +} + +KDE_NO_EXPORT bool MPlayer::contrast (int val, bool /*absolute*/) { + QString cmd; + cmd.sprintf ("contrast %d 1", val); + return sendCommand (cmd); +} + +KDE_NO_EXPORT bool MPlayer::brightness (int val, bool /*absolute*/) { + QString cmd; + cmd.sprintf ("brightness %d 1", val); + return sendCommand (cmd); +} + +bool MPlayer::run (const char * args, const char * pipe) { + //m_view->consoleOutput ()->clear (); + m_process_output = QString (); + connect (m_process, SIGNAL (receivedStdout (KProcess *, char *, int)), + this, SLOT (processOutput (KProcess *, char *, int))); + connect (m_process, SIGNAL (receivedStderr (KProcess *, char *, int)), + this, SLOT (processOutput (KProcess *, char *, int))); + m_use_slave = !(pipe && pipe[0]); + if (!m_use_slave) { + fprintf (stderr, "%s | ", pipe); + *m_process << pipe << " | "; + } + QString exe = m_configpage->mplayer_path; + if (exe.isEmpty ()) + exe = "mplayer"; + fprintf (stderr, "%s -wid %lu ", exe.ascii(), (unsigned long) widget ()); + *m_process << exe << " -wid " << QString::number (widget ()); + + if (m_use_slave) { + fprintf (stderr, "-slave "); + *m_process << "-slave "; + } + + QString strVideoDriver = QString (m_settings->videodrivers[m_settings->videodriver].driver); + if (!strVideoDriver.isEmpty ()) { + fprintf (stderr, " -vo %s", strVideoDriver.lower().ascii()); + *m_process << " -vo " << strVideoDriver.lower(); + if (viewer ()->view ()->keepSizeRatio () && + strVideoDriver.lower() == QString::fromLatin1 ("x11")) { + fprintf (stderr, " -zoom"); + *m_process << " -zoom"; + } + } + QString strAudioDriver = QString (m_settings->audiodrivers[m_settings->audiodriver].driver); + if (!strAudioDriver.isEmpty ()) { + fprintf (stderr, " -ao %s", strAudioDriver.lower().ascii()); + *m_process << " -ao " << strAudioDriver.lower(); + } + if (m_settings->framedrop) { + fprintf (stderr, " -framedrop"); + *m_process << " -framedrop"; + } + + if (m_configpage->additionalarguments.length () > 0) { + fprintf (stderr, " %s", m_configpage->additionalarguments.ascii()); + *m_process << " " << m_configpage->additionalarguments; + } + // postproc thingies + + fprintf (stderr, " %s", m_source->filterOptions ().ascii ()); + *m_process << " " << m_source->filterOptions (); + + if (m_settings->autoadjustcolors) { + fprintf (stderr, " -contrast %d", m_settings->contrast); + *m_process << " -contrast " << QString::number (m_settings->contrast); + + fprintf (stderr, " -brightness %d", m_settings->brightness); + *m_process << " -brightness " <<QString::number(m_settings->brightness); + + fprintf (stderr, " -hue %d", m_settings->hue); + *m_process << " -hue " << QString::number (m_settings->hue); + + fprintf (stderr, " -saturation %d", m_settings->saturation); + *m_process << " -saturation " <<QString::number(m_settings->saturation); + } + if (aid > -1) { + fprintf (stderr, " -aid %d", aid); + *m_process << " -aid " << QString::number (aid); + } + + if (sid > -1) { + fprintf (stderr, " -sid %d", sid); + *m_process << " -sid " << QString::number (sid); + } + for (NodePtr n = m_mrl; n; n = n->parentNode ()) { + if (n->id != id_node_group_node && n->id != id_node_playlist_item) + break; + QString plops = convertNode <Element> (n)->getAttribute ("mplayeropts"); + if (!plops.isNull ()) { + QStringList sl = QStringList::split (QChar (' '), plops); + for (int i = 0; i < sl.size (); ++i) { + QString plop = KProcess::quote (sl[i]); + fprintf (stderr, " %s", plop.ascii ()); + *m_process << " " << plop; + } + break; + } + } + + fprintf (stderr, " %s\n", args); + *m_process << " " << args; + + QValueList<QCString>::const_iterator it; + QString sMPArgs; + QValueList<QCString>::const_iterator end( m_process->args().end() ); + for ( it = m_process->args().begin(); it != end; ++it ){ + sMPArgs += (*it); + } + m_process->start (KProcess::NotifyOnExit, KProcess::All); + + old_volume = viewer ()->view ()->controlPanel ()->volumeBar ()->value (); + + if (m_process->isRunning ()) { + setState (Buffering); // wait for start regexp for state Playing + return true; + } + return false; +} + +KDE_NO_EXPORT bool MPlayer::grabPicture (const KURL & url, int pos) { + stop (); + initProcess (viewer ()); + QString outdir = locateLocal ("data", "kmplayer/"); + m_grabfile = outdir + QString ("00000001.jpg"); + unlink (m_grabfile.ascii ()); + QString myurl (url.isLocalFile () ? getPath (url) : url.url ()); + QString args ("mplayer "); + if (m_settings->mplayerpost090) + args += "-vo jpeg:outdir="; + else + args += "-vo jpeg -jpeg outdir="; + args += KProcess::quote (outdir); + args += QString (" -frames 1 -nosound -quiet "); + if (pos > 0) + args += QString ("-ss %1 ").arg (pos); + args += KProcess::quote (QString (QFile::encodeName (myurl))); + *m_process << args; + kdDebug () << args << endl; + m_process->start (KProcess::NotifyOnExit, KProcess::NoCommunication); + return m_process->isRunning (); +} + +KDE_NO_EXPORT void MPlayer::processOutput (KProcess *, char * str, int slen) { + if (!viewer () || slen <= 0) return; + View * v = viewer ()->view (); + + bool ok; + QRegExp * patterns = m_configpage->m_patterns; + QRegExp & m_refURLRegExp = patterns[MPlayerPreferencesPage::pat_refurl]; + QRegExp & m_refRegExp = patterns[MPlayerPreferencesPage::pat_ref]; + do { + int len = strcspn (str, "\r\n"); + QString out = m_process_output + QString::fromLocal8Bit (str, len); + m_process_output = QString (); + str += len; + slen -= len; + if (slen <= 0) { + m_process_output = out; + break; + } + bool process_stats = false; + if (str[0] == '\r') { + if (slen > 1 && str[1] == '\n') { + str++; + slen--; + } else + process_stats = true; + } + str++; + slen--; + + if (process_stats) { + QRegExp & m_posRegExp = patterns[MPlayerPreferencesPage::pat_pos]; + QRegExp & m_cacheRegExp = patterns[MPlayerPreferencesPage::pat_cache]; + if (m_source->hasLength () && m_posRegExp.search (out) > -1) { + int pos = int (10.0 * m_posRegExp.cap (1).toFloat ()); + m_source->setPosition (pos); + m_request_seek = -1; + } else if (m_cacheRegExp.search (out) > -1) { + m_source->setLoading (int (m_cacheRegExp.cap(1).toDouble())); + } + } else if (out.startsWith ("ID_LENGTH")) { + int pos = out.find ('='); + if (pos > 0) { + int l = (int) out.mid (pos + 1).toDouble (&ok); + if (ok && l >= 0) { + m_source->setLength (m_mrl, 10 * l); + } + } + } else if (m_refURLRegExp.search(out) > -1) { + kdDebug () << "Reference mrl " << m_refURLRegExp.cap (1) << endl; + if (!m_tmpURL.isEmpty () && m_url != m_tmpURL) + m_source->insertURL (m_mrl, m_tmpURL);; + m_tmpURL = KURL::fromPathOrURL (m_refURLRegExp.cap (1)).url (); + if (m_source->url () == m_tmpURL || m_url == m_tmpURL) + m_tmpURL.truncate (0); + } else if (m_refRegExp.search (out) > -1) { + kdDebug () << "Reference File " << endl; + m_tmpURL.truncate (0); + } else if (out.startsWith ("ID_VIDEO_WIDTH")) { + int pos = out.find ('='); + if (pos > 0) { + int w = out.mid (pos + 1).toInt (); + m_source->setDimensions (m_mrl, w, m_source->height ()); + } + } else if (out.startsWith ("ID_VIDEO_HEIGHT")) { + int pos = out.find ('='); + if (pos > 0) { + int h = out.mid (pos + 1).toInt (); + m_source->setDimensions (m_mrl, m_source->width (), h); + } + } else if (out.startsWith ("ID_VIDEO_ASPECT")) { + int pos = out.find ('='); + if (pos > 0) { + bool ok; + QString val = out.mid (pos + 1); + float a = val.toFloat (&ok); + if (!ok) { + val.replace (',', '.'); + a = val.toFloat (&ok); + } + if (ok && a > 0.001) + m_source->setAspect (m_mrl, a); + } + } else if (out.startsWith ("ID_AID_")) { + int pos = out.find ('_', 7); + if (pos > 0) { + int id = out.mid (7, pos - 7).toInt (); + pos = out.find ('=', pos); + if (pos > 0) { + if (!alanglist_end) { + alanglist = new LangInfo (id, out.mid (pos + 1)); + alanglist_end = alanglist; + } else { + alanglist_end->next = new LangInfo (id, out.mid(pos+1)); + alanglist_end = alanglist_end->next; + } + kdDebug () << "lang " << id << " " << alanglist_end->name <<endl; + } + } + } else if (out.startsWith ("ID_SID_")) { + int pos = out.find ('_', 7); + if (pos > 0) { + int id = out.mid (7, pos - 7).toInt (); + pos = out.find ('=', pos); + if (pos > 0) { + if (!slanglist_end) { + slanglist = new LangInfo (id, out.mid (pos + 1)); + slanglist_end = slanglist; + } else { + slanglist_end->next = new LangInfo (id, out.mid(pos+1)); + slanglist_end = slanglist_end->next; + } + kdDebug () << "sid " << id << " " << slanglist_end->name <<endl; + } + } + } else if (out.startsWith ("ICY Info")) { + int p = out.find ("StreamTitle=", 8); + if (p > -1) { + p += 12; + int e = out.find (';', p); + if (e > -1) + e -= p; + ((PlayListNotify *)m_source)->setInfoMessage (out.mid (p, e)); + } + } else { + QRegExp & m_startRegExp = patterns[MPlayerPreferencesPage::pat_start]; + QRegExp & m_sizeRegExp = patterns[MPlayerPreferencesPage::pat_size]; + v->addText (out, true); + if (!m_source->processOutput (out)) { + // int movie_width = m_source->width (); + if (/*movie_width <= 0 &&*/ m_sizeRegExp.search (out) > -1) { + int movie_width = m_sizeRegExp.cap (1).toInt (&ok); + int movie_height = ok ? m_sizeRegExp.cap (2).toInt (&ok) : 0; + if (ok && movie_width > 0 && movie_height > 0) { + m_source->setDimensions(m_mrl,movie_width,movie_height); + m_source->setAspect (m_mrl, 1.0*movie_width/movie_height); + } + } else if (m_startRegExp.search (out) > -1) { + if (m_settings->mplayerpost090) { + if (!m_tmpURL.isEmpty () && m_url != m_tmpURL) { + m_source->insertURL (m_mrl, m_tmpURL);; + m_tmpURL.truncate (0); + } + m_source->setIdentified (); + } + QStringList alst, slst; + for (SharedPtr <LangInfo> li = alanglist; li; li = li->next) + alst.push_back (li->name); + for (SharedPtr <LangInfo> li = slanglist; li; li = li->next) + slst.push_back (li->name); + m_source->setLanguages (alst, slst); + setState (Playing); + } + } + } + } while (slen > 0); +} + +KDE_NO_EXPORT void MPlayer::processStopped (KProcess * p) { + if (p && !m_grabfile.isEmpty ()) { + emit grabReady (m_grabfile); + m_grabfile.truncate (0); + } else if (p) { + QString url; + if (!m_source->identified ()) { + m_source->setIdentified (); + if (!m_tmpURL.isEmpty () && m_url != m_tmpURL) { + m_source->insertURL (m_mrl, m_tmpURL);; + m_tmpURL.truncate (0); + } + } + if (m_source && m_needs_restarted) { + commands.clear (); + int pos = m_source->position (); + play (m_source, m_mrl); + seek (pos, true); + } else + MPlayerBase::processStopped (p); + } +} + +void MPlayer::setAudioLang (int id, const QString &) { + SharedPtr <LangInfo> li = alanglist; + for (; id > 0 && li; li = li->next) + id--; + if (li) + aid = li->id; + m_needs_restarted = true; + sendCommand (QString ("quit")); +} + +void MPlayer::setSubtitle (int id, const QString &) { + SharedPtr <LangInfo> li = slanglist; + for (; id > 0 && li; li = li->next) + id--; + if (li) + sid = li->id; + m_needs_restarted = true; + sendCommand (QString ("quit")); +} + +//----------------------------------------------------------------------------- + +extern const char * strMPlayerGroup; +static const char * strMPlayerPatternGroup = "MPlayer Output Matching"; +static const char * strMPlayerPath = "MPlayer Path"; +static const char * strAddArgs = "Additional Arguments"; +static const char * strCacheSize = "Cache Size for Streaming"; +static const char * strAlwaysBuildIndex = "Always build index"; +static const int non_patterns = 4; + +static struct MPlayerPattern { + QString caption; + const char * name; + const char * pattern; +} _mplayer_patterns [] = { + { i18n ("Size pattern"), "Movie Size", "VO:.*[^0-9]([0-9]+)x([0-9]+)" }, + { i18n ("Cache pattern"), "Cache Fill", "Cache fill:[^0-9]*([0-9\\.]+)%" }, + { i18n ("Position pattern"), "Movie Position", "V:\\s*([0-9\\.]+)" }, + { i18n ("Index pattern"), "Index Pattern", "Generating Index: +([0-9]+)%" }, + { i18n ("Reference URL pattern"), "Reference URL Pattern", "Playing\\s+(.*[^\\.])\\.?\\s*$" }, + { i18n ("Reference pattern"), "Reference Pattern", "Reference Media file" }, + { i18n ("Start pattern"), "Start Playing", "Start[^ ]* play" }, + { i18n ("DVD language pattern"), "DVD Language", "\\[open].*audio.*language: ([A-Za-z]+).*aid.*[^0-9]([0-9]+)" }, + { i18n ("DVD subtitle pattern"), "DVD Sub Title", "\\[open].*subtitle.*[^0-9]([0-9]+).*language: ([A-Za-z]+)" }, + { i18n ("DVD titles pattern"), "DVD Titles", "There are ([0-9]+) titles" }, + { i18n ("DVD chapters pattern"), "DVD Chapters", "There are ([0-9]+) chapters" }, + { i18n ("VCD track pattern"), "VCD Tracks", "track ([0-9]+):" }, + { i18n ("Audio CD tracks pattern"), "CDROM Tracks", "[Aa]udio CD[^0-9]+([0-9]+)[^0-9]tracks" } +}; + +namespace KMPlayer { + +class KMPLAYER_NO_EXPORT MPlayerPreferencesFrame : public QFrame { +public: + MPlayerPreferencesFrame (QWidget * parent); + QTable * table; +}; + +} // namespace + +KDE_NO_CDTOR_EXPORT MPlayerPreferencesFrame::MPlayerPreferencesFrame (QWidget * parent) + : QFrame (parent) { + QVBoxLayout * layout = new QVBoxLayout (this); + table = new QTable (int (MPlayerPreferencesPage::pat_last)+non_patterns, 2, this); + table->verticalHeader ()->hide (); + table->setLeftMargin (0); + table->horizontalHeader ()->hide (); + table->setTopMargin (0); + table->setColumnReadOnly (0, true); + table->setText (0, 0, i18n ("MPlayer command:")); + table->setText (1, 0, i18n ("Additional command line arguments:")); + table->setText (2, 0, QString("%1 (%2)").arg (i18n ("Cache size:")).arg (i18n ("kB"))); // FIXME for new translations + table->setCellWidget (2, 1, new QSpinBox (0, 32767, 32, table->viewport())); + table->setText (3, 0, i18n ("Build new index when possible")); + table->setCellWidget (3, 1, new QCheckBox (table->viewport())); + QWhatsThis::add (table->cellWidget (3, 1), i18n ("Allows seeking in indexed files (AVIs)")); + for (int i = 0; i < int (MPlayerPreferencesPage::pat_last); i++) + table->setText (i+non_patterns, 0, _mplayer_patterns[i].caption); + QFontMetrics metrics (table->font ()); + int first_column_width = 50; + for (int i = 0; i < int (MPlayerPreferencesPage::pat_last+non_patterns); i++) { + int strwidth = metrics.boundingRect (table->text (i, 0)).width (); + if (strwidth > first_column_width) + first_column_width = strwidth + 4; + } + table->setColumnWidth (0, first_column_width); + table->setColumnStretchable (1, true); + layout->addWidget (table); +} + +KDE_NO_CDTOR_EXPORT MPlayerPreferencesPage::MPlayerPreferencesPage (MPlayer * p) + : m_process (p), m_configframe (0L) { +} + +KDE_NO_EXPORT void MPlayerPreferencesPage::write (KConfig * config) { + config->setGroup (strMPlayerPatternGroup); + for (int i = 0; i < int (pat_last); i++) + config->writeEntry + (_mplayer_patterns[i].name, m_patterns[i].pattern ()); + config->setGroup (strMPlayerGroup); + config->writeEntry (strMPlayerPath, mplayer_path); + config->writeEntry (strAddArgs, additionalarguments); + config->writeEntry (strCacheSize, cachesize); + config->writeEntry (strAlwaysBuildIndex, alwaysbuildindex); +} + +KDE_NO_EXPORT void MPlayerPreferencesPage::read (KConfig * config) { + config->setGroup (strMPlayerPatternGroup); + for (int i = 0; i < int (pat_last); i++) + m_patterns[i].setPattern (config->readEntry + (_mplayer_patterns[i].name, _mplayer_patterns[i].pattern)); + config->setGroup (strMPlayerGroup); + mplayer_path = config->readEntry (strMPlayerPath, "mplayer"); + additionalarguments = config->readEntry (strAddArgs); + cachesize = config->readNumEntry (strCacheSize, 384); + alwaysbuildindex = config->readBoolEntry (strAlwaysBuildIndex, false); +} + +KDE_NO_EXPORT void MPlayerPreferencesPage::sync (bool fromUI) { + QTable * table = m_configframe->table; + QSpinBox * cacheSize = static_cast<QSpinBox *>(table->cellWidget (2, 1)); + QCheckBox * buildIndex = static_cast<QCheckBox *>(table->cellWidget (3, 1)); + if (fromUI) { + mplayer_path = table->text (0, 1); + additionalarguments = table->text (1, 1); + for (int i = 0; i < int (pat_last); i++) + m_patterns[i].setPattern (table->text (i+non_patterns, 1)); + cachesize = cacheSize->value(); + alwaysbuildindex = buildIndex->isChecked (); + } else { + table->setText (0, 1, mplayer_path); + table->setText (1, 1, additionalarguments); + for (int i = 0; i < int (pat_last); i++) + table->setText (i+non_patterns, 1, m_patterns[i].pattern ()); + if (cachesize > 0) + cacheSize->setValue(cachesize); + buildIndex->setChecked (alwaysbuildindex); + } +} + +KDE_NO_EXPORT void MPlayerPreferencesPage::prefLocation (QString & item, QString & icon, QString & tab) { + item = i18n ("General Options"); + icon = QString ("kmplayer"); + tab = i18n ("MPlayer"); +} + +KDE_NO_EXPORT QFrame * MPlayerPreferencesPage::prefPage (QWidget * parent) { + m_configframe = new MPlayerPreferencesFrame (parent); + return m_configframe; +} + +//----------------------------------------------------------------------------- + +static const char * mencoder_supports [] = { + "dvdsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L +}; + +KDE_NO_CDTOR_EXPORT MEncoder::MEncoder (QObject * parent, Settings * settings) + : MPlayerBase (parent, settings, "mencoder") { + m_supported_sources = mencoder_supports; +} + +KDE_NO_CDTOR_EXPORT MEncoder::~MEncoder () { +} + +KDE_NO_EXPORT void MEncoder::init () { +} + +bool MEncoder::deMediafiedPlay () { + bool success = false; + stop (); + initProcess (viewer ()); + KURL url (m_url); + m_source->setPosition (0); + QString args; + m_use_slave = m_source->pipeCmd ().isEmpty (); + if (!m_use_slave) + args = m_source->pipeCmd () + QString (" | "); + QString margs = m_settings->mencoderarguments; + if (m_settings->recordcopy) + margs = QString ("-oac copy -ovc copy"); + args += QString ("mencoder ") + margs + ' ' + m_source->recordCmd (); + // FIXME if (m_player->source () == source) // ugly + // m_player->stop (); + QString myurl = url.isLocalFile () ? getPath (url) : url.url (); + bool post090 = m_settings->mplayerpost090; + if (!myurl.isEmpty ()) { + if (!post090 && myurl.startsWith (QString ("tv://"))) + ; // skip it + else if (!post090 && myurl.startsWith (QString ("vcd://"))) + args += myurl.replace (0, 6, QString (" -vcd ")); + else if (!post090 && myurl.startsWith (QString ("dvd://"))) + args += myurl.replace (0, 6, QString (" -dvd ")); + else + args += ' ' + KProcess::quote (QString (QFile::encodeName (myurl))); + } + QString outurl = KProcess::quote (QString (QFile::encodeName (m_recordurl.isLocalFile () ? getPath (m_recordurl) : m_recordurl.url ()))); + kdDebug () << args << " -o " << outurl << endl; + *m_process << args << " -o " << outurl; + m_process->start (KProcess::NotifyOnExit, KProcess::NoCommunication); + success = m_process->isRunning (); + if (success) + setState (Playing); + return success; +} + +KDE_NO_EXPORT bool MEncoder::stop () { + terminateJobs (); + if (!m_source || !m_process || !m_process->isRunning ()) return true; + kdDebug () << "MEncoder::stop ()" << endl; + if (m_use_slave) + m_process->kill (SIGINT); + return MPlayerBase::stop (); +} + +//----------------------------------------------------------------------------- + +static const char * mplayerdump_supports [] = { + "dvdsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L +}; + +KDE_NO_CDTOR_EXPORT +MPlayerDumpstream::MPlayerDumpstream (QObject * parent, Settings * settings) + : MPlayerBase (parent, settings, "mplayerdumpstream") { + m_supported_sources = mplayerdump_supports; + } + +KDE_NO_CDTOR_EXPORT MPlayerDumpstream::~MPlayerDumpstream () { +} + +KDE_NO_EXPORT void MPlayerDumpstream::init () { +} + +bool MPlayerDumpstream::deMediafiedPlay () { + bool success = false; + stop (); + initProcess (viewer ()); + KURL url (m_url); + m_source->setPosition (0); + QString args; + m_use_slave = m_source->pipeCmd ().isEmpty (); + if (!m_use_slave) + args = m_source->pipeCmd () + QString (" | "); + args += QString ("mplayer ") + m_source->recordCmd (); + // FIXME if (m_player->source () == source) // ugly + // m_player->stop (); + QString myurl = url.isLocalFile () ? getPath (url) : url.url (); + bool post090 = m_settings->mplayerpost090; + if (!myurl.isEmpty ()) { + if (!post090 && myurl.startsWith (QString ("tv://"))) + ; // skip it + else if (!post090 && myurl.startsWith (QString ("vcd://"))) + args += myurl.replace (0, 6, QString (" -vcd ")); + else if (!post090 && myurl.startsWith (QString ("dvd://"))) + args += myurl.replace (0, 6, QString (" -dvd ")); + else + args += ' ' + KProcess::quote (QString (QFile::encodeName (myurl))); + } + QString outurl = KProcess::quote (QString (QFile::encodeName (m_recordurl.isLocalFile () ? getPath (m_recordurl) : m_recordurl.url ()))); + kdDebug () << args << " -dumpstream -dumpfile " << outurl << endl; + *m_process << args << " -dumpstream -dumpfile " << outurl; + m_process->start (KProcess::NotifyOnExit, KProcess::NoCommunication); + success = m_process->isRunning (); + if (success) + setState (Playing); + return success; +} + +KDE_NO_EXPORT bool MPlayerDumpstream::stop () { + terminateJobs (); + if (!m_source || !m_process || !m_process->isRunning ()) return true; + kdDebug () << "MPlayerDumpstream::stop ()" << endl; + if (m_use_slave) + m_process->kill (SIGINT); + return MPlayerBase::stop (); +} + +//----------------------------------------------------------------------------- + +static int callback_counter = 0; + +Callback::Callback (CallbackProcess * process) + : DCOPObject (QString (QString ("KMPlayerCallback-") + + QString::number (callback_counter++)).ascii ()), + m_process (process) {} + +void Callback::statusMessage (int code, QString msg) { + if (!m_process->m_source) return; + switch ((StatusCode) code) { + case stat_newtitle: + //m_process->source ()->setTitle (msg); + if (m_process->viewer ()) + ((PlayListNotify *) m_process->source ())->setInfoMessage (msg); + break; + case stat_hasvideo: + if (m_process->viewer ()) + m_process->viewer ()->view ()->videoStart (); + break; + default: + m_process->setStatusMessage (msg); + }; +} + +void Callback::subMrl (QString mrl, QString title) { + if (!m_process->m_source) return; + m_process->m_source->insertURL (m_process->m_mrl, KURL::fromPathOrURL (mrl).url (), title); + if (m_process->m_mrl && m_process->m_mrl->active ()) + m_process->m_mrl->defer (); // Xine detected this is a playlist +} + +void Callback::errorMessage (int code, QString msg) { + m_process->setErrorMessage (code, msg); +} + +void Callback::finished () { + m_process->setFinished (); +} + +void Callback::playing () { + m_process->setPlaying (); +} + +void Callback::started (QCString dcopname, QByteArray data) { + m_process->setStarted (dcopname, data); +} + +void Callback::movieParams (int length, int w, int h, float aspect, QStringList alang, QStringList slang) { + m_process->setMovieParams (length, w, h, aspect, alang, slang); +} + +void Callback::moviePosition (int position) { + m_process->setMoviePosition (position); +} + +void Callback::loadingProgress (int percentage) { + m_process->setLoadingProgress (percentage); +} + +void Callback::toggleFullScreen () { + Viewer * v = m_process->viewer (); + if (v) + v->view ()->fullScreen (); +} + +//----------------------------------------------------------------------------- + +CallbackProcess::CallbackProcess (QObject * parent, Settings * settings, const char * n, const QString & menuname) + : Process (parent, settings, n), + m_callback (new Callback (this)), + m_backend (0L), + m_menuname (menuname), + m_configpage (new XMLPreferencesPage (this)), + in_gui_update (false), + m_have_config (config_unknown), + m_send_config (send_no) { +} + +CallbackProcess::~CallbackProcess () { + delete m_callback; + delete m_configpage; + if (configdoc) + configdoc->document()->dispose (); +} + +void CallbackProcess::setStatusMessage (const QString & /*msg*/) { +} + +QString CallbackProcess::menuName () const { + return m_menuname; +} + +void CallbackProcess::setErrorMessage (int code, const QString & msg) { + kdDebug () << "setErrorMessage " << code << " " << msg << endl; + if (code == 0 && m_send_config != send_no) { + if (m_send_config == send_new) + stop (); + m_send_config = send_no; + } +} + +void CallbackProcess::setFinished () { + setState (Ready); +} + +void CallbackProcess::setPlaying () { + setState (Playing); +} + +void CallbackProcess::setStarted (QCString dcopname, QByteArray & data) { + if (data.size ()) + m_configdata = data; + kdDebug () << "up and running " << dcopname << endl; + m_backend = new Backend_stub (dcopname, "Backend"); + if (m_send_config == send_new) { + m_backend->setConfig (m_changeddata); + } + if (m_have_config == config_probe || m_have_config == config_unknown) { + bool was_probe = m_have_config == config_probe; + m_have_config = data.size () ? config_yes : config_no; + if (m_have_config == config_yes) { + configdoc = new ConfigDocument (); + QTextStream ts (data, IO_ReadOnly); + readXML (configdoc, ts, QString ()); + configdoc->normalize (); + //kdDebug () << mydoc->innerText () << endl; + } + emit configReceived (); + if (m_configpage) + m_configpage->sync (false); + if (was_probe) { + quit (); + return; + } + } + if (m_settings->autoadjustcolors) { + saturation (m_settings->saturation, true); + hue (m_settings->hue, true); + brightness (m_settings->brightness, true); + contrast (m_settings->contrast, true); + } + setState (Ready); +} + +void CallbackProcess::setMovieParams (int len, int w, int h, float a, const QStringList & alang, const QStringList & slang) { + kdDebug () << "setMovieParams " << len << " " << w << "," << h << " " << a << endl; + if (!m_source) return; + in_gui_update = true; + m_source->setDimensions (m_mrl, w, h); + m_source->setAspect (m_mrl, a); + m_source->setLength (m_mrl, len); + m_source->setLanguages (alang, slang); + in_gui_update = false; +} + +void CallbackProcess::setMoviePosition (int position) { + if (!m_source) return; + in_gui_update = true; + m_source->setPosition (position); + m_request_seek = -1; + in_gui_update = false; +} + +void CallbackProcess::setLoadingProgress (int percentage) { + in_gui_update = true; + m_source->setLoading (percentage); + in_gui_update = false; +} + +bool CallbackProcess::getConfigData () { + if (m_have_config == config_no) + return false; + if (m_have_config == config_unknown && !playing ()) { + m_have_config = config_probe; + ready (viewer ()); + } + return true; +} + +void CallbackProcess::setChangedData (const QByteArray & data) { + m_changeddata = data; + m_send_config = playing () ? send_try : send_new; + if (m_send_config == send_try) + m_backend->setConfig (data); + else + ready (viewer ()); +} + +bool CallbackProcess::deMediafiedPlay () { + if (!m_backend) + return false; + kdDebug () << "CallbackProcess::play " << m_url << endl; + QString u = m_url; + if (u == "tv://" && !m_source->tuner ().isEmpty ()) { + u = "v4l:/" + m_source->tuner (); + if (m_source->frequency () > 0) + u += QChar ('/') + QString::number (m_source->frequency ()); + } + KURL url (u); + QString myurl = url.isLocalFile () ? getPath (url) : url.url (); + m_backend->setURL (myurl); + const KURL & sub_url = m_source->subUrl (); + if (!sub_url.isEmpty ()) + m_backend->setSubTitleURL (QString (QFile::encodeName (sub_url.isLocalFile () ? QFileInfo (getPath (sub_url)).absFilePath () : sub_url.url ()))); + if (m_source->frequency () > 0) + m_backend->frequency (m_source->frequency ()); + m_backend->play (m_mrl ? m_mrl->mrl ()->repeat : 0); + setState (Buffering); + return true; +} + +bool CallbackProcess::stop () { + terminateJobs (); + if (!m_process || !m_process->isRunning () || m_state < Buffering) + return true; + kdDebug () << "CallbackProcess::stop ()" << m_backend << endl; + if (m_backend) + m_backend->stop (); + return true; +} + +bool CallbackProcess::quit () { + if (m_have_config == config_probe) + m_have_config = config_unknown; // hmm + if (m_send_config == send_new) + m_send_config = send_no; // oh well + if (playing ()) { + kdDebug () << "CallbackProcess::quit ()" << endl; + if (m_backend) + m_backend->quit (); + else if (viewer ()) + viewer ()->sendKeyEvent ('q'); +#if KDE_IS_VERSION(3, 1, 90) + m_process->wait(1); +#else + QTime t; + t.start (); + do { + KProcessController::theKProcessController->waitForProcessExit (2); + } while (t.elapsed () < 1000 && m_process->isRunning ()); +#endif + } + return Process::quit (); +} + +bool CallbackProcess::pause () { + if (!playing () || !m_backend) return false; + m_backend->pause (); + return true; +} + +void CallbackProcess::setAudioLang (int id, const QString & al) { + if (!m_backend) return; + m_backend->setAudioLang (id, al); +} + +void CallbackProcess::setSubtitle (int id, const QString & sl) { + if (!m_backend) return; + m_backend->setSubtitle (id, sl); +} + +bool CallbackProcess::seek (int pos, bool absolute) { + if (in_gui_update || !playing () || + !m_backend || !m_source || + !m_source->hasLength () || + (absolute && m_source->position () == pos)) + return false; + if (!absolute) + pos = m_source->position () + pos; + m_source->setPosition (pos); + if (m_request_seek < 0) + m_backend->seek (pos, true); + m_request_seek = pos; + return true; +} + +bool CallbackProcess::volume (int val, bool b) { + if (m_backend) + m_backend->volume (int (sqrt (val*100)), b); + //m_backend->volume (100 * log (1.0*val) / log (100.0), b); + return !!m_backend; +} + +bool CallbackProcess::saturation (int val, bool b) { + if (m_backend) + m_backend->saturation (val, b); + return !!m_backend; +} + +bool CallbackProcess::hue (int val, bool b) { + if (m_backend) + m_backend->hue (val, b); + return !!m_backend; +} + +bool CallbackProcess::brightness (int val, bool b) { + if (m_backend) + m_backend->brightness (val, b); + return !!m_backend; +} + +bool CallbackProcess::contrast (int val, bool b) { + if (m_backend) + m_backend->contrast (val, b); + return !!m_backend; +} + +QString CallbackProcess::dcopName () { + QString cbname; + cbname.sprintf ("%s/%s", QString (kapp->dcopClient ()->appId ()).ascii (), + QString (m_callback->objId ()).ascii ()); + return cbname; +} + +void CallbackProcess::initProcess (Viewer * viewer) { + Process::initProcess (viewer); + connect (m_process, SIGNAL (processExited (KProcess *)), + this, SLOT (processStopped (KProcess *))); + connect (m_process, SIGNAL (receivedStdout (KProcess *, char *, int)), + this, SLOT (processOutput (KProcess *, char *, int))); + connect (m_process, SIGNAL (receivedStderr (KProcess *, char *, int)), + this, SLOT (processOutput (KProcess *, char *, int))); +} + +KDE_NO_EXPORT void CallbackProcess::processOutput (KProcess *, char * str, int slen) { + if (viewer () && slen > 0) + viewer ()->view ()->addText (QString::fromLocal8Bit (str, slen)); +} + +KDE_NO_EXPORT void CallbackProcess::processStopped (KProcess *) { + if (m_source) + ((PlayListNotify *) m_source)->setInfoMessage (QString ()); + delete m_backend; + m_backend = 0L; + setState (NotRunning); + if (m_send_config == send_try) { + m_send_config = send_new; // we failed, retry .. + ready (viewer ()); + } +} + +WId CallbackProcess::widget () { + return viewer () ? viewer ()->embeddedWinId () : 0; +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT ConfigDocument::ConfigDocument () + : Document (QString ()) {} + +KDE_NO_CDTOR_EXPORT ConfigDocument::~ConfigDocument () { + kdDebug () << "~ConfigDocument" << endl; +} + +namespace KMPlayer { + /* + * Element for ConfigDocument + */ + struct KMPLAYER_NO_EXPORT SomeNode : public ConfigNode { + KDE_NO_CDTOR_EXPORT SomeNode (NodePtr & d, const QString & t) + : ConfigNode (d, t) {} + KDE_NO_CDTOR_EXPORT ~SomeNode () {} + NodePtr childFromTag (const QString & t); + }; +} // namespace + +KDE_NO_CDTOR_EXPORT ConfigNode::ConfigNode (NodePtr & d, const QString & t) + : DarkNode (d, t), w (0L) {} + +NodePtr ConfigDocument::childFromTag (const QString & tag) { + if (tag.lower () == QString ("document")) + return new ConfigNode (m_doc, tag); + return 0L; +} + +NodePtr ConfigNode::childFromTag (const QString & t) { + return new TypeNode (m_doc, t); +} + +KDE_NO_CDTOR_EXPORT TypeNode::TypeNode (NodePtr & d, const QString & t) + : ConfigNode (d, t), tag (t) {} + +NodePtr TypeNode::childFromTag (const QString & tag) { + return new SomeNode (m_doc, tag); +} + +NodePtr SomeNode::childFromTag (const QString & t) { + return new SomeNode (m_doc, t); +} + +QWidget * TypeNode::createWidget (QWidget * parent) { + QString type_attr = getAttribute (StringPool::attr_type); + const char * ctype = type_attr.ascii (); + QString value = getAttribute (StringPool::attr_value); + if (!strcmp (ctype, "range")) { + w = new QSlider (getAttribute (QString ("START")).toInt (), + getAttribute (StringPool::attr_end).toInt (), + 1, value.toInt (), Qt::Horizontal, parent); + } else if (!strcmp (ctype, "num") || !strcmp (ctype, "string")) { + w = new QLineEdit (value, parent); + } else if (!strcmp (ctype, "bool")) { + QCheckBox * checkbox = new QCheckBox (parent); + checkbox->setChecked (value.toInt ()); + w = checkbox; + } else if (!strcmp (ctype, "enum")) { + QComboBox * combo = new QComboBox (parent); + for (NodePtr e = firstChild (); e; e = e->nextSibling ()) + if (e->isElementNode () && !strcmp (e->nodeName (), "item")) + combo->insertItem (convertNode <Element> (e)->getAttribute (StringPool::attr_value)); + combo->setCurrentItem (value.toInt ()); + w = combo; + } else if (!strcmp (ctype, "tree")) { + } else + kdDebug() << "Unknown type:" << ctype << endl; + return w; +} + +void TypeNode::changedXML (QTextStream & out) { + if (!w) return; + QString type_attr = getAttribute (StringPool::attr_type); + const char * ctype = type_attr.ascii (); + QString value = getAttribute (StringPool::attr_value); + QString newvalue; + if (!strcmp (ctype, "range")) { + newvalue = QString::number (static_cast <QSlider *> (w)->value ()); + } else if (!strcmp (ctype, "num") || !strcmp (ctype, "string")) { + newvalue = static_cast <QLineEdit *> (w)->text (); + } else if (!strcmp (ctype, "bool")) { + newvalue = QString::number (static_cast <QCheckBox *> (w)->isChecked()); + } else if (!strcmp (ctype, "enum")) { + newvalue = QString::number (static_cast<QComboBox *>(w)->currentItem()); + } else if (!strcmp (ctype, "tree")) { + } else + kdDebug() << "Unknown type:" << ctype << endl; + if (value != newvalue) { + value = newvalue; + setAttribute (StringPool::attr_value, newvalue); + out << outerXML (); + } +} + +//----------------------------------------------------------------------------- + +namespace KMPlayer { + +class KMPLAYER_NO_EXPORT XMLPreferencesFrame : public QFrame { +public: + XMLPreferencesFrame (QWidget * parent, CallbackProcess *); + KDE_NO_CDTOR_EXPORT ~XMLPreferencesFrame () {} + QTable * table; +protected: + void showEvent (QShowEvent *); +private: + CallbackProcess * m_process; +}; + +} // namespace + +KDE_NO_CDTOR_EXPORT XMLPreferencesFrame::XMLPreferencesFrame +(QWidget * parent, CallbackProcess * p) + : QFrame (parent), m_process (p){ + QVBoxLayout * layout = new QVBoxLayout (this); + table = new QTable (this); + layout->addWidget (table); +} + +KDE_NO_CDTOR_EXPORT XMLPreferencesPage::XMLPreferencesPage (CallbackProcess * p) + : m_process (p), m_configframe (0L) { +} + +KDE_NO_CDTOR_EXPORT XMLPreferencesPage::~XMLPreferencesPage () { +} + +KDE_NO_EXPORT void XMLPreferencesFrame::showEvent (QShowEvent *) { + if (!m_process->haveConfig ()) + m_process->getConfigData (); +} + +KDE_NO_EXPORT void XMLPreferencesPage::write (KConfig *) { +} + +KDE_NO_EXPORT void XMLPreferencesPage::read (KConfig *) { +} + +KDE_NO_EXPORT void XMLPreferencesPage::sync (bool fromUI) { + if (!m_configframe) return; + QTable * table = m_configframe->table; + int row = 0; + if (fromUI) { + NodePtr configdoc = m_process->configDocument (); + if (!configdoc || m_configframe->table->numCols () < 1) //not yet created + return; + NodePtr elm = configdoc->firstChild (); // document + if (!elm || !elm->hasChildNodes ()) { + kdDebug () << "No valid data" << endl; + return; + } + QString str; + QTextStream ts (&str, IO_WriteOnly); + ts << "<document>"; + for (NodePtr e = elm->firstChild (); e; e = e->nextSibling ()) + convertNode <TypeNode> (e)->changedXML (ts); + if (str.length () > 10) { + ts << "</document>"; + QByteArray changeddata = QCString (str.ascii ()); + kdDebug () << str << " " << changeddata.size () << str.length () << endl; + changeddata.resize (str.length ()); + m_process->setChangedData (changeddata); + } + } else { + if (!m_process->haveConfig ()) + return; + NodePtr configdoc = m_process->configDocument (); + if (!configdoc) + return; + if (m_configframe->table->numCols () < 1) { // not yet created + QString err; + int first_column_width = 50; + NodePtr elm = configdoc->firstChild (); // document + if (!elm || !elm->hasChildNodes ()) { + kdDebug () << "No valid data" << endl; + return; + } + // set up the table fields + table->setNumCols (2); + table->setNumRows (elm->childNodes ()->length ()); + table->verticalHeader ()->hide (); + table->setLeftMargin (0); + table->horizontalHeader ()->hide (); + table->setTopMargin (0); + table->setColumnReadOnly (0, true); + QFontMetrics metrics (table->font ()); + for (elm=elm->firstChild (); elm; elm=elm->nextSibling (), row++) { + TypeNode * tn = convertNode <TypeNode> (elm); + QString name = tn->getAttribute (StringPool::attr_name); + m_configframe->table->setText (row, 0, name); + int strwid = metrics.boundingRect (name).width (); + if (strwid > first_column_width) + first_column_width = strwid + 4; + QWidget * w = tn->createWidget (table->viewport ()); + if (w) { + table->setCellWidget (row, 1, w); + QWhatsThis::add (w, elm->innerText ()); + } else + kdDebug () << "No widget for " << name; + } + table->setColumnWidth (0, first_column_width); + table->setColumnStretchable (1, true); + } + } +} + +KDE_NO_EXPORT void XMLPreferencesPage::prefLocation (QString & item, QString & icon, QString & tab) { + item = i18n ("General Options"); + icon = QString ("kmplayer"); + tab = m_process->menuName (); +} + +KDE_NO_EXPORT QFrame * XMLPreferencesPage::prefPage (QWidget * parent) { + m_configframe = new XMLPreferencesFrame (parent, m_process); + return m_configframe; +} + +//----------------------------------------------------------------------------- + +static const char * xine_supported [] = { + "dvdnavsource", "dvdsource", "exitsource", "introsource", "pipesource", + "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L +}; + +KDE_NO_CDTOR_EXPORT Xine::Xine (QObject * parent, Settings * settings) + : CallbackProcess (parent, settings, "xine", i18n ("&Xine")) { +#ifdef HAVE_XINE + m_supported_sources = xine_supported; + m_settings->addPage (m_configpage); +#endif +} + +KDE_NO_CDTOR_EXPORT Xine::~Xine () {} + +bool Xine::ready (Viewer * viewer) { + initProcess (viewer); + viewer->changeProtocol (QXEmbed::XPLAIN); + QString xine_config = KProcess::quote (QString (QFile::encodeName (locateLocal ("data", "kmplayer/") + QString ("xine_config")))); + m_request_seek = -1; + if (m_source && !m_source->pipeCmd ().isEmpty ()) { + fprintf (stderr, "%s | ", m_source->pipeCmd ().ascii ()); + *m_process << m_source->pipeCmd ().ascii () << " | "; + } + fprintf (stderr, "kxineplayer -wid %lu", (unsigned long) widget ()); + *m_process << "kxineplayer -wid " << QString::number (widget ()); + fprintf (stderr, " -f %s", xine_config.ascii ()); + *m_process << " -f " << xine_config; + + QString strVideoDriver = QString (m_settings->videodrivers[m_settings->videodriver].driver); + if (!strVideoDriver.isEmpty ()) { + fprintf (stderr, " -vo %s", strVideoDriver.lower().ascii()); + *m_process << " -vo " << strVideoDriver.lower(); + } + QString strAudioDriver = QString (m_settings->audiodrivers[m_settings->audiodriver].driver); + if (!strAudioDriver.isEmpty ()) { + if (strAudioDriver.startsWith (QString ("alsa"))) + strAudioDriver = QString ("alsa"); + fprintf (stderr, " -ao %s", strAudioDriver.lower().ascii()); + *m_process << " -ao " << strAudioDriver.lower(); + } + fprintf (stderr, " -cb %s", dcopName ().ascii()); + *m_process << " -cb " << dcopName (); + if (m_have_config == config_unknown || m_have_config == config_probe) { + fprintf (stderr, " -c"); + *m_process << " -c"; + } + if (m_source) + if (m_source->url ().url ().startsWith (QString ("dvd://")) && + !m_settings->dvddevice.isEmpty ()) { + fprintf (stderr, " -dvd-device %s", m_settings->dvddevice.ascii ()); + *m_process << " -dvd-device " << m_settings->dvddevice; + } else if (m_source->url ().url ().startsWith (QString ("vcd://")) && + !m_settings->vcddevice.isEmpty ()) { + fprintf (stderr, " -vcd-device %s", m_settings->vcddevice.ascii ()); + *m_process << " -vcd-device " << m_settings->vcddevice; + } else if (m_source->url ().url ().startsWith (QString ("tv://")) && + !m_source->videoDevice ().isEmpty ()) { + fprintf (stderr, " -vd %s", m_source->videoDevice ().ascii ()); + *m_process << " -vd " << m_source->videoDevice (); + } + if (!m_recordurl.isEmpty ()) { + QString rf = KProcess::quote ( + QString (QFile::encodeName (getPath (m_recordurl)))); + fprintf (stderr, " -rec %s", rf.ascii ()); + *m_process << " -rec " << rf; + } + fprintf (stderr, "\n"); + m_process->start (KProcess::NotifyOnExit, KProcess::All); + return m_process->isRunning (); +} + +// TODO:input.v4l_video_device_path input.v4l_radio_device_path +// v4l:/Webcam/0 v4l:/Television/21600 v4l:/Radio/96 + +//----------------------------------------------------------------------------- + +static const char * gst_supported [] = { + "exitsource", "introsource", "urlsource", "vcdsource", "audiocdsource", 0L +}; + +KDE_NO_CDTOR_EXPORT GStreamer::GStreamer (QObject * parent, Settings * settings) + : CallbackProcess (parent, settings, "gstreamer", i18n ("&GStreamer")) { +#ifdef HAVE_GSTREAMER + m_supported_sources = gst_supported; +#endif +} + +KDE_NO_CDTOR_EXPORT GStreamer::~GStreamer () {} + +KDE_NO_EXPORT bool GStreamer::ready (Viewer * viewer) { + initProcess (viewer); + viewer->changeProtocol (QXEmbed::XPLAIN); + m_request_seek = -1; + fprintf (stderr, "kgstplayer -wid %lu", (unsigned long) widget ()); + *m_process << "kgstplayer -wid " << QString::number (widget ()); + + QString strVideoDriver = QString (m_settings->videodrivers[m_settings->videodriver].driver); + if (!strVideoDriver.isEmpty ()) { + fprintf (stderr, " -vo %s", strVideoDriver.lower().ascii()); + *m_process << " -vo " << strVideoDriver.lower(); + } + QString strAudioDriver = QString (m_settings->audiodrivers[m_settings->audiodriver].driver); + if (!strAudioDriver.isEmpty ()) { + if (strAudioDriver.startsWith (QString ("alsa"))) + strAudioDriver = QString ("alsa"); + fprintf (stderr, " -ao %s", strAudioDriver.lower().ascii()); + *m_process << " -ao " << strAudioDriver.lower(); + } + fprintf (stderr, " -cb %s", dcopName ().ascii()); + *m_process << " -cb " << dcopName (); + if (m_source) + if (m_source->url ().url ().startsWith (QString ("dvd://")) && + !m_settings->dvddevice.isEmpty ()) { + fprintf (stderr, " -dvd-device %s", m_settings->dvddevice.ascii ()); + *m_process << " -dvd-device " << m_settings->dvddevice; + } else if (m_source->url ().url ().startsWith (QString ("vcd://")) && + !m_settings->vcddevice.isEmpty ()) { + fprintf (stderr, " -vcd-device %s", m_settings->vcddevice.ascii ()); + *m_process << " -vcd-device " << m_settings->vcddevice; + } + fprintf (stderr, "\n"); + m_process->start (KProcess::NotifyOnExit, KProcess::All); + return m_process->isRunning (); +} + +//----------------------------------------------------------------------------- + +static const char * ffmpeg_supports [] = { + "tvsource", "urlsource", 0L +}; + +FFMpeg::FFMpeg (QObject * parent, Settings * settings) + : Process (parent, settings, "ffmpeg") { + m_supported_sources = ffmpeg_supports; +} + +KDE_NO_CDTOR_EXPORT FFMpeg::~FFMpeg () { +} + +KDE_NO_EXPORT void FFMpeg::init () { +} + +bool FFMpeg::deMediafiedPlay () { + initProcess (viewer ()); + KURL url (m_url); + connect (m_process, SIGNAL (processExited (KProcess *)), + this, SLOT (processStopped (KProcess *))); + QString outurl = QString (QFile::encodeName (m_recordurl.isLocalFile () ? getPath (m_recordurl) : m_recordurl.url ())); + if (m_recordurl.isLocalFile ()) + QFile (outurl).remove (); + QString cmd ("ffmpeg "); + if (!m_source->videoDevice ().isEmpty () || + !m_source->audioDevice ().isEmpty ()) { + if (!m_source->videoDevice ().isEmpty ()) + cmd += QString ("-vd ") + m_source->videoDevice (); + else + cmd += QString ("-vn"); + if (!m_source->audioDevice ().isEmpty ()) + cmd += QString (" -ad ") + m_source->audioDevice (); + else + cmd += QString (" -an"); + KProcess process; + process.setUseShell (true); + if (!m_source->videoNorm ().isEmpty ()) { + process << "v4lctl -c " << m_source->videoDevice () << " setnorm " << m_source->videoNorm (); + kdDebug () << "v4lctl -c " << m_source->videoDevice () << " setnorm " << m_source->videoNorm () << endl; + process.start (KProcess::Block); + cmd += QString (" -tvstd ") + m_source->videoNorm (); + } + if (m_source->frequency () > 0) { + process.clearArguments(); + process << "v4lctl -c " << m_source->videoDevice () << " setfreq " << QString::number (m_source->frequency ()); + kdDebug () << "v4lctl -c " << m_source->videoDevice () << " setfreq " << m_source->frequency () << endl; + process.start (KProcess::Block); + } + } else { + cmd += QString ("-i ") + KProcess::quote (QString (QFile::encodeName (url.isLocalFile () ? getPath (url) : url.url ()))); + } + cmd += QChar (' ') + m_settings->ffmpegarguments; + cmd += QChar (' ') + KProcess::quote (QString (QFile::encodeName (outurl))); + fprintf (stderr, "%s\n", (const char *) cmd.local8Bit ()); + *m_process << cmd; + // FIXME if (m_player->source () == source) // ugly + // m_player->stop (); + m_process->start (KProcess::NotifyOnExit, KProcess::All); + if (m_process->isRunning ()) + setState (Playing); + return m_process->isRunning (); +} + +KDE_NO_EXPORT bool FFMpeg::stop () { + terminateJobs (); + if (!playing ()) return true; + kdDebug () << "FFMpeg::stop" << endl; + m_process->writeStdin ("q", 1); + return true; +} + +KDE_NO_EXPORT bool FFMpeg::quit () { + stop (); + if (!playing ()) return true; + QTime t; + t.start (); + do { + KProcessController::theKProcessController->waitForProcessExit (2); + } while (t.elapsed () < 2000 && m_process->isRunning ()); + return Process::quit (); +} + +KDE_NO_EXPORT void FFMpeg::processStopped (KProcess *) { + setState (NotRunning); +} + +//----------------------------------------------------------------------------- + +#ifdef HAVE_NSPR + +struct KMPLAYER_NO_EXPORT DBusStatic { + DBusStatic (); + ~DBusStatic (); + DBusQt::Connection *connection; // FIXME find a way to detect if already connected + DBusConnection *dbus_connnection; +}; + +static DBusStatic * dbus_static = 0L; + +DBusStatic::DBusStatic () + : connection (new DBusQt::Connection (DBUS_BUS_SESSION, 0L)), + dbus_connnection (0L) {} + +DBusStatic::~DBusStatic () { + dbus_connection_unref (dbus_connnection); + delete connection; + dbus_static = 0L; +} + +static KStaticDeleter <DBusStatic> dbus_static_deleter; + +//------------------%<--------------------------------------------------------- + +static DBusHandlerResult +dbusFilter (DBusConnection *conn, DBusMessage *msg, void *data) { + DBusMessageIter args; + //const char *iface = "org.kde.kmplayer.backend"; + NpPlayer *process = (NpPlayer *) data; + const char * iface = process->interface ().ascii (); + const char * path = dbus_message_get_path (msg); + + if (dbus_message_has_destination (msg, process->destination ().ascii ()) && + dbus_message_has_interface (msg, iface) && + QString (path).startsWith(process->objectPath ())) + { + //kdDebug () << "dbusFilter " << sender << + // " iface:" << dbus_message_get_interface (msg) << + // " member:" << dbus_message_get_member (msg) << + // " dest:" << dbus_message_get_destination (msg) << endl; + + if (dbus_message_is_method_call (msg, iface, "getUrl")) { + char *param = 0; + QString url, target; + if (dbus_message_iter_init (msg, &args) && + DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic (&args, ¶m); + url = QString::fromLocal8Bit (param); + if (dbus_message_iter_next (&args) && + DBUS_TYPE_STRING==dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic (&args, ¶m); + target = QString::fromLocal8Bit (param); + } + process->requestStream (path, url, target); + } + //kdDebug () << "getUrl " << param << endl; + + } else if (dbus_message_is_method_call (msg, iface, "evaluate")) { + char *param = 0; + if (dbus_message_iter_init (msg, &args) && + DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic (&args, ¶m); + QString r = process->evaluateScript (QString::fromUtf8 (param)); + DBusMessage * rmsg = dbus_message_new_method_return (msg); + char *res = strdup (r.utf8 ().data ()); + //kdDebug () << "evaluate => " << res << endl; + dbus_message_append_args (rmsg, + DBUS_TYPE_STRING, &res, + DBUS_TYPE_INVALID); + dbus_connection_send (conn, rmsg, NULL); + dbus_connection_flush (conn); + dbus_message_unref (rmsg); + free (res); + } + + } else if (dbus_message_is_method_call (msg, iface, "destroy")) { + QString stream =QString(path).mid(process->objectPath().length()+1); + process->destroyStream (stream); + + } else if (dbus_message_is_method_call (msg, iface, "running")) { + char *param = 0; + if (dbus_message_iter_init (msg, &args) && + DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic (&args, ¶m); + process->setStarted (QString (param)); + } + + } else if (dbus_message_is_method_call (msg, iface, "plugged")) { + process->viewer ()->view ()->videoStart (); + } else if (dbus_message_is_method_call (msg, iface, "dimension")) { + Q_UINT32 w, h; + if (dbus_message_iter_init (msg, &args) && + DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic (&args, &w); + if (dbus_message_iter_next (&args) && + DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)) { + dbus_message_iter_get_basic (&args, &h); + if (h > 0) + process->source ()->setAspect (process->mrl(), 1.0*w/h); + } + } + } + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +KDE_NO_CDTOR_EXPORT +NpStream::NpStream (QObject *p, Q_UINT32 sid, const KURL & u) + : QObject (p), + url (u), + job (0L), bytes (0), content_length (0), + stream_id (sid), + finish_reason (NoReason) { + data_arrival.tv_sec = 0; +} + +KDE_NO_CDTOR_EXPORT NpStream::~NpStream () { + close (); +} + +KDE_NO_EXPORT void NpStream::open () { + kdDebug () << "NpStream " << stream_id << " open " << url.url () << endl; + if (url.url().startsWith ("javascript:")) { + NpPlayer *npp = static_cast <NpPlayer *> (parent ()); + QString result = npp->evaluateScript (url.url().mid (11)); + if (!result.isEmpty ()) { + QCString cr = result.local8Bit (); + int len = cr.length (); + pending_buf.resize (len + 1); + memcpy (pending_buf.data (), cr.data (), len); + pending_buf.data ()[len] = 0; + gettimeofday (&data_arrival, 0L); + } + kdDebug () << "result is " << pending_buf.data () << endl; + finish_reason = BecauseDone; + emit stateChanged (); + } else { + job = KIO::get (url, false, false); + job->addMetaData ("errorPage", "false"); + connect (job, SIGNAL (data (KIO::Job *, const QByteArray &)), + this, SLOT (slotData (KIO::Job *, const QByteArray &))); + connect (job, SIGNAL (result (KIO::Job *)), + this, SLOT (slotResult (KIO::Job *))); + connect (job, SIGNAL (redirection (KIO::Job *, const KURL &)), + this, SLOT (redirection (KIO::Job *, const KURL &))); + connect (job, SIGNAL (mimetype (KIO::Job *, const QString &)), + SLOT (slotMimetype (KIO::Job *, const QString &))); + connect (job, SIGNAL (totalSize (KIO::Job *, KIO::filesize_t)), + SLOT (slotTotalSize (KIO::Job *, KIO::filesize_t))); + } +} + +KDE_NO_EXPORT void NpStream::close () { + if (job) { + job->kill (); // quiet, no result signal + job = 0L; + finish_reason = BecauseStopped; + // don't emit stateChanged(), because always triggered from NpPlayer + } +} + +KDE_NO_EXPORT void NpStream::slotResult (KIO::Job *jb) { + kdDebug() << "slotResult " << bytes << " err:" << jb->error () << endl; + finish_reason = jb->error () ? BecauseError : BecauseDone; + job = 0L; // signal KIO::Job::result deletes itself + emit stateChanged (); +} + +KDE_NO_EXPORT void NpStream::slotData (KIO::Job*, const QByteArray& qb) { + pending_buf = qb; // we suspend job, so qb should be valid until resume + if (qb.size()) { + job->suspend (); + gettimeofday (&data_arrival, 0L); + emit stateChanged (); + } +} + +KDE_NO_EXPORT void NpStream::redirection (KIO::Job *, const KURL &u) { + url = u; + emit redirected (stream_id, url); +} + +void NpStream::slotMimetype (KIO::Job *, const QString &mime) { + mimetype = mime; +} + +void NpStream::slotTotalSize (KIO::Job *, KIO::filesize_t sz) { + content_length = sz; +} + +static const char * npplayer_supports [] = { + "urlsource", 0L +}; + +KDE_NO_CDTOR_EXPORT +NpPlayer::NpPlayer (QObject * parent, Settings * settings, const QString & srv) + : Process (parent, settings, "npp"), + service (srv), + write_in_progress (false) { + m_supported_sources = npplayer_supports; +} + +KDE_NO_CDTOR_EXPORT NpPlayer::~NpPlayer () { + if (!iface.isEmpty ()) { + DBusError dberr; + dbus_error_init (&dberr); + DBusConnection *conn = dbus_static->dbus_connnection; + if (conn) { + dbus_bus_remove_match (conn, filter.ascii(), &dberr); + if (dbus_error_is_set (&dberr)) + dbus_error_free (&dberr); + dbus_connection_remove_filter (conn, dbusFilter, this); + dbus_connection_flush (conn); + } + } +} + +KDE_NO_EXPORT void NpPlayer::init () { +} + +KDE_NO_EXPORT void NpPlayer::initProcess (Viewer * viewer) { + Process::initProcess (viewer); + connect (m_process, SIGNAL (processExited (KProcess *)), + this, SLOT (processStopped (KProcess *))); + connect (m_process, SIGNAL (receivedStdout (KProcess *, char *, int)), + this, SLOT (processOutput (KProcess *, char *, int))); + connect (m_process, SIGNAL (receivedStderr (KProcess *, char *, int)), + this, SLOT (processOutput (KProcess *, char *, int))); + connect (m_process, SIGNAL (wroteStdin (KProcess *)), + this, SLOT (wroteStdin (KProcess *))); + if (!dbus_static) + dbus_static = dbus_static_deleter.setObject (new DBusStatic ()); + if (iface.isEmpty ()) { + DBusError dberr; + iface = QString ("org.kde.kmplayer.callback"); + static int count = 0; + path = QString ("/npplayer%1").arg (count++); + filter = QString ("type='method_call',interface='org.kde.kmplayer.callback'"); + + dbus_error_init (&dberr); + DBusConnection *conn = dbus_bus_get (DBUS_BUS_SESSION, &dberr); + if (dbus_error_is_set (&dberr)) + dbus_error_free (&dberr); + if (!conn) { + kdError () << "Failed to get dbus connection: " << dberr.message << endl; + return; + } + bool has_service = !service.isEmpty(); + if (has_service) { // standalone kmplayer + dbus_bus_request_name (conn, service.ascii(), + DBUS_NAME_FLAG_DO_NOT_QUEUE, &dberr); + if (dbus_error_is_set (&dberr)) { + kdError () << "Failed to register name " << service << ": " << dberr.message; + dbus_error_free (&dberr); + has_service = false; + } + } + if (!has_service) // plugin, accept what-is [sic] + service = QString (dbus_bus_get_unique_name (conn)); + kdDebug() << "using service " << service << " interface " << iface << endl; + dbus_bus_add_match (conn, filter.ascii(), &dberr); + if (dbus_error_is_set (&dberr)) { + kdError () << "Failed to set match " << filter << ": " << dberr.message << endl; + dbus_error_free (&dberr); + } + dbus_connection_add_filter (conn, dbusFilter, this, 0L); + dbus_connection_flush (conn); + dbus_static->dbus_connnection = conn; + } +} + +KDE_NO_EXPORT bool NpPlayer::deMediafiedPlay () { + kdDebug() << "NpPlayer::play '" << m_url << "'" << endl; + // if we change from XPLAIN to XEMBED, the DestroyNotify may come later + viewer ()->changeProtocol (QXEmbed::XEMBED); + if (m_mrl && !m_url.isEmpty () && dbus_static->dbus_connnection) { + QString mime = "text/plain"; + QString plugin; + Element *elm = m_mrl->mrl (); + if (elm->id == id_node_html_object) { + // this sucks to have to do this here .. + for (NodePtr n = elm->firstChild (); n; n = n->nextSibling ()) + if (n->id == KMPlayer::id_node_html_embed) { + elm = convertNode <Element> (n); + break; + } + } + for (NodePtr n = m_mrl; n; n = n->parentNode ()) { + Mrl *mrl = n->mrl (); + if (mrl && m_base_url.isEmpty ()) + m_base_url = mrl->getAttribute ("pluginbaseurl"); + if (mrl && !mrl->mimetype.isEmpty ()) { + plugin = m_source->plugin (mrl->mimetype); + kdDebug() << "search plugin " << mrl->mimetype << "->" << plugin << endl; + if (!plugin.isEmpty ()) { + mime = mrl->mimetype; + break; + } + } + } + if (!plugin.isEmpty ()) { + DBusMessage *msg = dbus_message_new_method_call ( + remote_service.ascii(), + "/plugin", + "org.kde.kmplayer.backend", + "play"); + char *c_url = strdup (m_url.local8Bit().data ()); + char *c_mime = strdup (mime.ascii ()); + char *c_plugin = strdup (plugin.ascii ()); + DBusMessageIter it; + dbus_message_iter_init_append (msg, &it); + dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &c_url); + dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &c_mime); + dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &c_plugin); + unsigned int param_len = elm->attributes ()->length (); + char **argn = (char **) malloc (param_len * sizeof (char *)); + char **argv = (char **) malloc (param_len * sizeof (char *)); + dbus_message_iter_append_basic (&it, DBUS_TYPE_UINT32, ¶m_len); + DBusMessageIter ait; + dbus_message_iter_open_container (&it, DBUS_TYPE_ARRAY,"{ss}",&ait); + AttributePtr a = elm->attributes ()->first (); + for (int i = 0; i < param_len && a; i++, a = a->nextSibling ()) { + DBusMessageIter dit; + dbus_message_iter_open_container (&ait, + DBUS_TYPE_DICT_ENTRY, + NULL, + &dit); + argn[i] = strdup (a->name ().toString ().local8Bit().data ()); + argv[i] = strdup (a->value ().local8Bit().data ()); + dbus_message_iter_append_basic (&dit, DBUS_TYPE_STRING, &argn[i]); + dbus_message_iter_append_basic (&dit, DBUS_TYPE_STRING, &argv[i]); + dbus_message_iter_close_container (&ait, &dit); + } + dbus_message_iter_close_container (&it, &ait); + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (dbus_static->dbus_connnection, msg, NULL); + dbus_message_unref (msg); + dbus_connection_flush (dbus_static->dbus_connnection); + free (c_url); + free (c_mime); + free (c_plugin); + for (int i = 0; i < param_len; i++) { + free (argn[i]); + free (argv[i]); + } + free (argn); + free (argv); + setState (Buffering); + return true; + } + } + stop (); + return false; +} + +KDE_NO_EXPORT bool NpPlayer::ready (Viewer * viewer) { + if (playing ()) + return true; // wait for callback + initProcess (viewer); + viewer->changeProtocol (QXEmbed::XEMBED); + kdDebug() << "NpPlayer::ready" << endl; + QString cmd ("knpplayer"); + cmd += QString (" -cb "); + cmd += service; + cmd += path; + cmd += QString (" -wid "); + cmd += QString::number (viewer->winId ()); + fprintf (stderr, "%s\n", cmd.local8Bit ().data ()); + *m_process << cmd; + m_process->start (KProcess::NotifyOnExit, KProcess::All); + return m_process->isRunning (); +} + +KDE_NO_EXPORT void NpPlayer::setStarted (const QString & srv) { + remote_service = srv; + kdDebug () << "NpPlayer::setStarted " << srv << endl; + setState (Ready); +} + +KDE_NO_EXPORT QString NpPlayer::evaluateScript (const QString & script) { + QString result; + emit evaluate (script, result); + //kdDebug () << "evaluateScript " << script << " => " << result << endl; + return result; +} + +static int getStreamId (const QString &path) { + int p = path.findRev (QChar ('_')); + if (p < 0) { + kdError() << "wrong object path " << path << endl; + return -1; + } + bool ok; + Q_UINT32 sid = path.mid (p+1).toInt (&ok); + if (!ok) { + kdError() << "wrong object path suffix " << path.mid (p+1) << endl; + return -1; + } + return sid; +} + +KDE_NO_EXPORT +void NpPlayer::requestStream (const QString &path, const QString & url, const QString & target) { + KURL uri (m_base_url.isEmpty () ? m_url : m_base_url, url); + kdDebug () << "NpPlayer::request " << path << " '" << uri << "'" << endl; + Q_UINT32 sid = getStreamId (path); + if (sid >= 0) { + if (!target.isEmpty ()) { + kdDebug () << "new page request " << target << endl; + if (url.startsWith ("javascript:")) { + QString result = evaluateScript (url.mid (11)); + kdDebug() << "result is " << result << endl; + if (result == "undefined") + uri = KURL (); + else + uri = KURL (m_url, result); // probably wrong .. + } + if (uri.isValid ()) + emit openUrl (uri, target); + sendFinish (sid, 0, NpStream::BecauseDone); + } else { + NpStream * ns = new NpStream (this, sid, uri); + connect (ns, SIGNAL (stateChanged ()), + this, SLOT (streamStateChanged ())); + streams[sid] = ns; + if (url != uri.url ()) + streamRedirected (sid, uri.url ()); + if (!write_in_progress) + processStreams (); + } + } +} + +KDE_NO_EXPORT void NpPlayer::destroyStream (const QString &s) { + int sid = getStreamId (s); + if (sid >= 0 && streams.contains ((Q_UINT32) sid)) { + NpStream *ns = streams[(Q_UINT32) sid]; + ns->close (); + if (!write_in_progress) + processStreams (); + } else { + kdWarning () << "Object " << s << " not found" << endl; + } +} + +KDE_NO_EXPORT +void NpPlayer::sendFinish (Q_UINT32 sid, Q_UINT32 bytes, NpStream::Reason because) { + if (playing () && dbus_static->dbus_connnection) { + Q_UINT32 reason = (int) because; + QString objpath = QString ("/plugin/stream_%1").arg (sid); + DBusMessage *msg = dbus_message_new_method_call ( + remote_service.ascii(), + objpath.ascii (), + "org.kde.kmplayer.backend", + "eof"); + dbus_message_append_args(msg, + DBUS_TYPE_UINT32, &bytes, + DBUS_TYPE_UINT32, &reason, + DBUS_TYPE_INVALID); + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (dbus_static->dbus_connnection, msg, NULL); + dbus_message_unref (msg); + dbus_connection_flush (dbus_static->dbus_connnection); + } +} + +KDE_NO_EXPORT void NpPlayer::terminateJobs () { + Process::terminateJobs (); + const StreamMap::iterator e = streams.end (); + for (StreamMap::iterator i = streams.begin (); i != e; ++i) + delete i.data (); + streams.clear (); +} + +KDE_NO_EXPORT bool NpPlayer::stop () { + terminateJobs (); + if (!playing ()) return true; + kdDebug () << "NpPlayer::stop " << endl; + if (dbus_static->dbus_connnection) { + DBusMessage *msg = dbus_message_new_method_call ( + remote_service.ascii(), + "/plugin", + "org.kde.kmplayer.backend", + "quit"); + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (dbus_static->dbus_connnection, msg, NULL); + dbus_message_unref (msg); + dbus_connection_flush (dbus_static->dbus_connnection); + } + return true; +} + +KDE_NO_EXPORT bool NpPlayer::quit () { + if (playing ()) { + stop (); + QTime t; + t.start (); + do { + KProcessController::theKProcessController->waitForProcessExit (2); + } while (t.elapsed () < 2000 && m_process->isRunning ()); + return Process::quit (); + } + return true; +} + +KDE_NO_EXPORT void NpPlayer::processOutput (KProcess *, char * str, int slen) { + if (viewer () && slen > 0) + viewer ()->view ()->addText (QString::fromLocal8Bit (str, slen)); +} + +KDE_NO_EXPORT void NpPlayer::processStopped (KProcess *) { + terminateJobs (); + if (m_source) + ((PlayListNotify *) m_source)->setInfoMessage (QString ()); + setState (NotRunning); +} + +KDE_NO_EXPORT void NpPlayer::streamStateChanged () { + setState (Playing); // hmm, this doesn't really fit in current states + if (!write_in_progress) + processStreams (); +} + +KDE_NO_EXPORT void NpPlayer::streamRedirected (Q_UINT32 sid, const KURL &u) { + if (playing () && dbus_static->dbus_connnection) { + kdDebug() << "redirected " << sid << " to " << u.url() << endl; + char *cu = strdup (u.url ().local8Bit().data ()); + QString objpath = QString ("/plugin/stream_%1").arg (sid); + DBusMessage *msg = dbus_message_new_method_call ( + remote_service.ascii(), + objpath.ascii (), + "org.kde.kmplayer.backend", + "redirected"); + dbus_message_append_args(msg, DBUS_TYPE_STRING, &cu, DBUS_TYPE_INVALID); + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (dbus_static->dbus_connnection, msg, NULL); + dbus_message_unref (msg); + dbus_connection_flush (dbus_static->dbus_connnection); + free (cu); + } +} + +KDE_NO_EXPORT void NpPlayer::processStreams () { + NpStream *stream = 0L; + Q_UINT32 stream_id; + timeval tv = { 0x7fffffff, 0 }; + const StreamMap::iterator e = streams.end (); + int active_count = 0; + //kdDebug() << "NpPlayer::processStreams " << streams.size() << endl; + for (StreamMap::iterator i = streams.begin (); i != e;) { + NpStream *ns = i.data (); + if (ns->job) { + active_count++; + } else if (active_count < 5 && + ns->finish_reason == NpStream::NoReason) { + write_in_progress = true; // javascript: urls emit stateChange + ns->open (); + write_in_progress = false; + if (ns->job) { + connect (ns, SIGNAL (redirected (Q_UINT32, const KURL&)), + this, SLOT (streamRedirected (Q_UINT32, const KURL&))); + active_count++; + } + } + if (ns->finish_reason == NpStream::BecauseStopped || + ns->finish_reason == NpStream::BecauseError || + (ns->finish_reason == NpStream::BecauseDone && + ns->pending_buf.size () == 0)) { + sendFinish (i.key(), ns->bytes, ns->finish_reason); + StreamMap::iterator ii = i; + ++ii; + streams.erase (i); + i = ii; + delete ns; + } else { + if (ns->pending_buf.size () > 0 && + (ns->data_arrival.tv_sec < tv.tv_sec || + (ns->data_arrival.tv_sec == tv.tv_sec && + ns->data_arrival.tv_usec < tv.tv_usec))) { + tv = ns->data_arrival; + stream = ns; + stream_id = i.key(); + } + ++i; + } + } + //kdDebug() << "NpPlayer::processStreams " << stream << endl; + if (stream) { + if (dbus_static->dbus_connnection && + !stream->bytes && + (!stream->mimetype.isEmpty() || stream->content_length)) { + char *mt = strdup (stream->mimetype.isEmpty () + ? "" + : stream->mimetype.utf8 ().data ()); + QString objpath=QString("/plugin/stream_%1").arg(stream->stream_id); + DBusMessage *msg = dbus_message_new_method_call ( + remote_service.ascii(), + objpath.ascii (), + "org.kde.kmplayer.backend", + "streamInfo"); + dbus_message_append_args (msg, + DBUS_TYPE_STRING, &mt, + DBUS_TYPE_UINT32, &stream->content_length, + DBUS_TYPE_INVALID); + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (dbus_static->dbus_connnection, msg, NULL); + dbus_message_unref (msg); + dbus_connection_flush (dbus_static->dbus_connnection); + free (mt); + } + const int header_len = 2 * sizeof (Q_UINT32); + Q_UINT32 chunk = stream->pending_buf.size(); + send_buf.resize (chunk + header_len); + memcpy (send_buf.data (), &stream_id, sizeof (Q_UINT32)); + memcpy (send_buf.data() + sizeof (Q_UINT32), &chunk, sizeof (Q_UINT32)); + memcpy (send_buf.data()+header_len, stream->pending_buf.data (), chunk); + stream->pending_buf = QByteArray (); + /*fprintf (stderr, " => %d %d\n", (long)stream_id, chunk);*/ + stream->bytes += chunk; + write_in_progress = true; + m_process->writeStdin (send_buf.data (), send_buf.size ()); + if (stream->finish_reason == NpStream::NoReason) + stream->job->resume (); + } +} + +KDE_NO_EXPORT void NpPlayer::wroteStdin (KProcess *) { + write_in_progress = false; + if (playing ()) + processStreams (); +} + +KDE_NO_EXPORT QString NpPlayer::menuName () const { + return i18n ("&Ice Ape"); +} + +#else + +KDE_NO_CDTOR_EXPORT +NpStream::NpStream (QObject *p, Q_UINT32, const KURL & url) + : QObject (p) {} + +KDE_NO_CDTOR_EXPORT NpStream::~NpStream () {} +void NpStream::slotResult (KIO::Job*) {} +void NpStream::slotData (KIO::Job*, const QByteArray&) {} +void NpStream::redirection (KIO::Job *, const KURL &) {} +void NpStream::slotMimetype (KIO::Job *, const QString &) {} +void NpStream::slotTotalSize (KIO::Job *, KIO::filesize_t) {} + +KDE_NO_CDTOR_EXPORT +NpPlayer::NpPlayer (QObject * parent, Settings * settings, const QString &) + : Process (parent, settings, "npp") {} +KDE_NO_CDTOR_EXPORT NpPlayer::~NpPlayer () {} +KDE_NO_EXPORT void NpPlayer::init () {} +KDE_NO_EXPORT bool NpPlayer::deMediafiedPlay () { return false; } +KDE_NO_EXPORT void NpPlayer::initProcess (Viewer *) {} +KDE_NO_EXPORT QString NpPlayer::menuName () const { return QString (); } +KDE_NO_EXPORT void NpPlayer::setStarted (const QString &) {} +KDE_NO_EXPORT bool NpPlayer::stop () { return false; } +KDE_NO_EXPORT bool NpPlayer::quit () { return false; } +KDE_NO_EXPORT bool NpPlayer::ready (Viewer *) { return false; } +KDE_NO_EXPORT void NpPlayer::processOutput (KProcess *, char *, int) {} +KDE_NO_EXPORT void NpPlayer::processStopped (KProcess *) {} +KDE_NO_EXPORT void NpPlayer::wroteStdin (KProcess *) {} +KDE_NO_EXPORT void NpPlayer::streamStateChanged () {} +KDE_NO_EXPORT void NpPlayer::streamRedirected (Q_UINT32, const KURL &) {} +KDE_NO_EXPORT void NpPlayer::terminateJobs () {} + +#endif + +#include "kmplayerprocess.moc" diff --git a/src/kmplayerprocess.h b/src/kmplayerprocess.h new file mode 100644 index 0000000..8a51702 --- /dev/null +++ b/src/kmplayerprocess.h @@ -0,0 +1,500 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2003 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPLAYERPROCESS_H_ +#define _KMPLAYERPROCESS_H_ + +#include <qobject.h> +#include <qguardedptr.h> +#include <qstring.h> +#include <qcstring.h> +#include <qstringlist.h> +#include <qregexp.h> + +#include <kurl.h> +#include <kio/global.h> + +#include "kmplayerconfig.h" +#include "kmplayersource.h" + +class QWidget; +class KProcess; + +namespace KIO { + class Job; + class TransferJob; +} + +namespace KMPlayer { + +class Settings; +class Viewer; +class Source; +class Callback; +class Backend_stub; + +/* + * Base class for all backend processes + */ +class KMPLAYER_EXPORT Process : public QObject { + Q_OBJECT +public: + enum State { + NotRunning = 0, Ready, Buffering, Playing + }; + Process (QObject * parent, Settings * settings, const char * n); + virtual ~Process (); + virtual void init (); + virtual void initProcess (Viewer *); + virtual QString menuName () const; + virtual void setAudioLang (int, const QString &); + virtual void setSubtitle (int, const QString &); + bool playing () const; + KDE_NO_EXPORT KProcess * process () const { return m_process; } + KDE_NO_EXPORT Source * source () const { return m_source; } + virtual WId widget (); + Viewer * viewer () const; + void setSource (Source * src) { m_source = src; } + virtual bool grabPicture (const KURL & url, int pos); + bool supports (const char * source) const; + State state () const { return m_state; } + NodePtr mrl () const { return m_mrl; } +signals: + void grabReady (const QString & path); +public slots: + virtual bool ready (Viewer *); + bool play (Source *, NodePtr mrl); + virtual bool stop (); + virtual bool quit (); + virtual bool pause (); + /* seek (pos, abs) seek position in deci-seconds */ + virtual bool seek (int pos, bool absolute); + /* volume from 0 to 100 */ + virtual bool volume (int pos, bool absolute); + /* saturation/hue/contrast/brightness from -100 to 100 */ + virtual bool saturation (int pos, bool absolute); + virtual bool hue (int pos, bool absolute); + virtual bool contrast (int pos, bool absolute); + virtual bool brightness (int pos, bool absolute); +protected slots: + void rescheduledStateChanged (); + void result (KIO::Job *); +protected: + void setState (State newstate); + virtual bool deMediafiedPlay (); + virtual void terminateJobs (); + Source * m_source; + Settings * m_settings; + NodePtrW m_mrl; + State m_state; + State m_old_state; + KProcess * m_process; + KIO::Job * m_job; + QString m_url; + int m_request_seek; + const char ** m_supported_sources; +private: + QGuardedPtr <Viewer> m_viewer; +}; + +/* + * Base class for all MPlayer based processes + */ +class MPlayerBase : public Process { + Q_OBJECT +public: + MPlayerBase (QObject * parent, Settings * settings, const char * n); + ~MPlayerBase (); + void initProcess (Viewer *); +public slots: + virtual bool stop (); + virtual bool quit (); +protected: + bool sendCommand (const QString &); + QStringList commands; + bool m_use_slave : 1; +protected slots: + virtual void processStopped (KProcess *); +private slots: + void dataWritten (KProcess *); +}; + +class MPlayerPreferencesPage; +class MPlayerPreferencesFrame; + +/* + * MPlayer process + */ +class KDE_EXPORT MPlayer : public MPlayerBase { + Q_OBJECT +public: + MPlayer (QObject * parent, Settings * settings); + ~MPlayer (); + virtual void init (); + virtual QString menuName () const; + virtual WId widget (); + virtual bool grabPicture (const KURL & url, int pos); + virtual void setAudioLang (int, const QString &); + virtual void setSubtitle (int, const QString &); + bool run (const char * args, const char * pipe = 0L); +public slots: + virtual bool deMediafiedPlay (); + virtual bool stop (); + virtual bool pause (); + virtual bool seek (int pos, bool absolute); + virtual bool volume (int pos, bool absolute); + virtual bool saturation (int pos, bool absolute); + virtual bool hue (int pos, bool absolute); + virtual bool contrast (int pos, bool absolute); + virtual bool brightness (int pos, bool absolute); + MPlayerPreferencesPage * configPage () const { return m_configpage; } + bool ready (Viewer *); +protected slots: + void processStopped (KProcess *); +private slots: + void processOutput (KProcess *, char *, int); +private: + QString m_process_output; + QString m_grabfile; + QWidget * m_widget; + MPlayerPreferencesPage * m_configpage; + QString m_tmpURL; + struct LangInfo { + LangInfo (int i, const QString & n) : id (i), name (n) {} + int id; QString name; SharedPtr <LangInfo> next; + }; + SharedPtr <LangInfo> alanglist; + WeakPtr <LangInfo> alanglist_end; + SharedPtr <LangInfo> slanglist; + WeakPtr <LangInfo> slanglist_end; + int aid, sid; + int old_volume; + bool m_needs_restarted; +}; + +/* + * MPlayer preferences page + */ +class KMPLAYER_NO_EXPORT MPlayerPreferencesPage : public PreferencesPage { +public: + enum Pattern { + pat_size = 0, pat_cache, pat_pos, pat_index, + pat_refurl, pat_ref, pat_start, + pat_dvdlang, pat_dvdsub, pat_dvdtitle, pat_dvdchapter, + pat_vcdtrack, pat_cdromtracks, + pat_last + }; + MPlayerPreferencesPage (MPlayer *); + KDE_NO_CDTOR_EXPORT ~MPlayerPreferencesPage () {} + void write (KConfig *); + void read (KConfig *); + void sync (bool fromUI); + void prefLocation (QString & item, QString & icon, QString & tab); + QFrame * prefPage (QWidget * parent); + QRegExp m_patterns[pat_last]; + int cachesize; + QString mplayer_path; + QString additionalarguments; + bool alwaysbuildindex; +private: + MPlayer * m_process; + MPlayerPreferencesFrame * m_configframe; +}; + +/* + * Base class for all recorders + */ +class KMPLAYER_EXPORT Recorder { +public: + KDE_NO_EXPORT const KURL & recordURL () const { return m_recordurl; } + KDE_NO_EXPORT void setURL (const KURL & url) { m_recordurl = url; } +protected: + KURL m_recordurl; +}; + +/* + * MEncoder recorder + */ +class MEncoder : public MPlayerBase, public Recorder { + Q_OBJECT +public: + MEncoder (QObject * parent, Settings * settings); + ~MEncoder (); + virtual void init (); + virtual bool deMediafiedPlay (); +public slots: + virtual bool stop (); +}; + +/* + * MPlayer recorder, runs 'mplayer -dumpstream' + */ +class KMPLAYER_NO_EXPORT MPlayerDumpstream + : public MPlayerBase, public Recorder { + Q_OBJECT +public: + MPlayerDumpstream (QObject * parent, Settings * settings); + ~MPlayerDumpstream (); + virtual void init (); + virtual bool deMediafiedPlay (); +public slots: + virtual bool stop (); +}; + +class XMLPreferencesPage; +class XMLPreferencesFrame; + +/* + * Base class for all backend processes having the KMPlayer::Backend interface + */ +class KMPLAYER_EXPORT CallbackProcess : public Process { + Q_OBJECT + friend class Callback; +public: + CallbackProcess (QObject * parent, Settings * settings, const char * n, const QString & menu); + ~CallbackProcess (); + virtual void setStatusMessage (const QString & msg); + virtual void setErrorMessage (int code, const QString & msg); + virtual void setFinished (); + virtual void setPlaying (); + virtual void setStarted (QCString dcopname, QByteArray & data); + virtual void setMovieParams (int length, int width, int height, float aspect, const QStringList & alang, const QStringList & slang); + virtual void setMoviePosition (int position); + virtual void setLoadingProgress (int percentage); + virtual void setAudioLang (int, const QString &); + virtual void setSubtitle (int, const QString &); + virtual QString menuName () const; + virtual WId widget (); + KDE_NO_EXPORT QByteArray & configData () { return m_configdata; } + KDE_NO_EXPORT bool haveConfig () { return m_have_config == config_yes; } + bool getConfigData (); + void setChangedData (const QByteArray &); + QString dcopName (); + NodePtr configDocument () { return configdoc; } + void initProcess (Viewer *); + virtual bool deMediafiedPlay (); +public slots: + bool stop (); + bool quit (); + bool pause (); + bool seek (int pos, bool absolute); + bool volume (int pos, bool absolute); + bool saturation (int pos, bool absolute); + bool hue (int pos, bool absolute); + bool contrast (int pos, bool absolute); + bool brightness (int pos, bool absolute); +signals: + void configReceived (); +protected slots: + void processStopped (KProcess *); + void processOutput (KProcess *, char *, int); +protected: + Callback * m_callback; + Backend_stub * m_backend; + QString m_menuname; + QByteArray m_configdata; + QByteArray m_changeddata; + XMLPreferencesPage * m_configpage; + NodePtr configdoc; + bool in_gui_update; + enum { config_unknown, config_probe, config_yes, config_no } m_have_config; + enum { send_no, send_try, send_new } m_send_config; +}; + +/* + * Config document as used by kxineplayer backend + */ +struct KMPLAYER_NO_EXPORT ConfigDocument : public Document { + ConfigDocument (); + ~ConfigDocument (); + NodePtr childFromTag (const QString & tag); +}; + +/* + * Element for ConfigDocument + */ +struct KMPLAYER_NO_EXPORT ConfigNode : public DarkNode { + ConfigNode (NodePtr & d, const QString & tag); + KDE_NO_CDTOR_EXPORT ~ConfigNode () {} + NodePtr childFromTag (const QString & tag); + QWidget * w; +}; + +/* + * Element for ConfigDocument, defining type of config item + */ +struct KMPLAYER_NO_EXPORT TypeNode : public ConfigNode { + TypeNode (NodePtr & d, const QString & t); + KDE_NO_CDTOR_EXPORT ~TypeNode () {} + NodePtr childFromTag (const QString & tag); + void changedXML (QTextStream & out); + QWidget * createWidget (QWidget * parent); + const char * nodeName () const { return tag.ascii (); } + QString tag; +}; + +/* + * Preference page for XML type of docuement + */ +class KMPLAYER_NO_EXPORT XMLPreferencesPage : public PreferencesPage { +public: + XMLPreferencesPage (CallbackProcess *); + ~XMLPreferencesPage (); + void write (KConfig *); + void read (KConfig *); + void sync (bool fromUI); + void prefLocation (QString & item, QString & icon, QString & tab); + QFrame * prefPage (QWidget * parent); +private: + CallbackProcess * m_process; + XMLPreferencesFrame * m_configframe; +}; + +/* + * Xine backend process + */ +class KMPLAYER_NO_EXPORT Xine : public CallbackProcess, public Recorder { + Q_OBJECT +public: + Xine (QObject * parent, Settings * settings); + ~Xine (); +public slots: + bool ready (Viewer *); +}; + +/* + * GStreamer backend process + */ +class KMPLAYER_NO_EXPORT GStreamer : public CallbackProcess { + Q_OBJECT +public: + GStreamer (QObject * parent, Settings * settings); + ~GStreamer (); +public slots: + virtual bool ready (Viewer *); +}; + +/* + * ffmpeg backend recorder + */ +class KMPLAYER_EXPORT FFMpeg : public Process, public Recorder { + Q_OBJECT +public: + FFMpeg (QObject * parent, Settings * settings); + ~FFMpeg (); + virtual void init (); + virtual bool deMediafiedPlay (); +public slots: + virtual bool stop (); + virtual bool quit (); +private slots: + void processStopped (KProcess *); +}; + +/* + * npplayer backend + */ + +class KMPLAYER_NO_EXPORT NpStream : public QObject { + Q_OBJECT +public: + enum Reason { + NoReason = -1, + BecauseDone = 0, BecauseError = 1, BecauseStopped = 2 + }; + + NpStream (QObject *parent, Q_UINT32 stream_id, const KURL & url); + ~NpStream (); + + void open (); + void close (); + + KURL url; + QByteArray pending_buf; + KIO::TransferJob *job; + timeval data_arrival; + Q_UINT32 bytes; + Q_UINT32 stream_id; + Q_UINT32 content_length; + Reason finish_reason; + QString mimetype; +signals: + void stateChanged (); + void redirected (Q_UINT32, const KURL &); +private slots: + void slotResult (KIO::Job*); + void slotData (KIO::Job*, const QByteArray& qb); + void redirection (KIO::Job *, const KURL &url); + void slotMimetype (KIO::Job *, const QString &mime); + void slotTotalSize (KIO::Job *, KIO::filesize_t sz); +}; + +class KMPLAYER_NO_EXPORT NpPlayer : public Process { + Q_OBJECT +public: + NpPlayer (QObject * parent, Settings * settings, const QString & srv); + ~NpPlayer (); + virtual void init (); + virtual bool deMediafiedPlay (); + virtual void initProcess (Viewer * viewer); + virtual QString menuName () const; + + void setStarted (const QString & srv); + void requestStream (const QString & path, const QString & url, const QString & target); + void destroyStream (const QString & path); + + KDE_NO_EXPORT const QString & destination () const { return service; } + KDE_NO_EXPORT const QString & interface () const { return iface; } + KDE_NO_EXPORT QString objectPath () const { return path; } + QString evaluateScript (const QString & scr); +signals: + void evaluate (const QString & scr, QString & result); + void openUrl (const KURL & url, const QString & target); +public slots: + virtual bool stop (); + virtual bool quit (); +public slots: + bool ready (Viewer *); +private slots: + void processOutput (KProcess *, char *, int); + void processStopped (KProcess *); + void wroteStdin (KProcess *); + void streamStateChanged (); + void streamRedirected (Q_UINT32, const KURL &); +protected: + virtual void terminateJobs (); +private: + void sendFinish (Q_UINT32 sid, Q_UINT32 total, NpStream::Reason because); + void processStreams (); + QString service; + QString iface; + QString path; + QString filter; + QString m_base_url; + typedef QMap <Q_UINT32, NpStream *> StreamMap; + StreamMap streams; + QString remote_service; + QByteArray send_buf; + bool write_in_progress; +}; + +} // namespace + +#endif //_KMPLAYERPROCESS_H_ diff --git a/src/kmplayerrc b/src/kmplayerrc new file mode 100644 index 0000000..cba3dad --- /dev/null +++ b/src/kmplayerrc @@ -0,0 +1,55 @@ +[General Options] +Show Statusbar=true +Show Toolbar=true +pipesource=xine +urlsource=xine +vcdsource=xine + +[KFileDialog Settings] + +[KFileDialog Speedbar] + +[MPlayer] +Post MPlayer 0.90=true +Add Configure Button=true +Additional Arguments= +Mencoder Arguments=-oac mp3lame -ovc lavc +Cache Size for Streaming=128 +DVD Device=/dev/dvd +Forward/Backward Seek Time=10 +Immediately Play DVD=true +Keep Size Ratio=true +Loop=false +Frame Drop=true +Add Record Button=true +Add Broadcast Button=true +Show DVD Menu=true +Video Driver=xv + +[Pipe Command] +Command1=cat ~/example.avi + +[MPlayer Output Matching] +DVD Chapters=There are ([0-9]+) chapters +DVD Language=ID_AID_([0-9]+)_LANG=([A-Za-z]+) +DVD Sub Title=ID_SID_([0-9]+)_LANG=([A-Za-z]+) +DVD Titles=There are ([0-9]+) titles +Movie Size=VO:.*[^0-9]([0-9]+)x([0-9]+) +Cache Fill=Cache fill:[^0-9]*([0-9\\.]+)% +Movie Position=V:\\s*([0-9\\.]+) +Start Playing=Start[^ ]* play +VCD Tracks=track ([0-9]+): + +[Broadcast] +Custom Setting=asf;mp3;32;22050;mpeg4;80;10;10;12;320;240;127.0.0.1;10.0.0.0 10.255.255.255;192.168.0.0 192.168.255.255 +Profile_Modem (32k)=asf;mp3;8;11025;mpeg4;50;19;3;3;160;128;27.0.0.1;10.0.0.0 10.255.255.255;192.168.0.0 192.168.255.255 +Profile_ISDN (64k)=asf;mp3;8;11025;mpeg4;50;16;3;3;320;240;127.0.0.1;10.0.0.0 10.255.255.255;192.168.0.0 192.168.255.255 +Profile_ISDN2 (128k)=asf;mp3;32;22050;mpeg4;80;10;10;12;320;240;127.0.0.1;10.0.0.0 10.255.255.255;192.168.0.0 192.168.255.255 +Profile_LAN (1024k)=mpeg;;64;44100;;512;5;25;12;320;240;127.0.0.1;10.0.0.0 10.255.255.255;192.168.0.0 192.168.255.255 +Profiles=Modem (32k);ISDN (64k);ISDN2 (128k);LAN (1024k) + +[Recent Files] + +[Recording] +Auto Play After Recording=0 +Recorder=3 diff --git a/src/kmplayershared.h b/src/kmplayershared.h new file mode 100644 index 0000000..3066b4c --- /dev/null +++ b/src/kmplayershared.h @@ -0,0 +1,264 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2004 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * until boost gets common, a more or less compatable one .. + */ + +#ifndef _SHAREDPTR_H_ +#define _SHAREDPTR_H_ + +//#define SHAREDPTR_DEBUG + +#ifdef SHAREDPTR_DEBUG +extern int shared_data_count; +#include <iostream> +#endif + +namespace KMPlayer { + +/** + * Shared data for SharedPtr and WeakPtr objects. + **/ +template <class T> +struct SharedData { + SharedData (T * t, bool w) : use_count (w?0:1), weak_count (1), ptr (t) { +#ifdef SHAREDPTR_DEBUG + std::cerr << "SharedData::SharedData use:" << use_count << " weak:" << weak_count << " total:" << ++shared_data_count << std::endl; +#endif + } +#ifdef SHAREDPTR_DEBUG + ~SharedData () { std::cerr << "SharedData::~SharedData" << " total:" << --shared_data_count << std::endl; } +#endif + void addRef (); + void addWeakRef (); + void release (); + void releaseWeak (); + void dispose (); + int use_count; + int weak_count; + T * ptr; +}; + +template <class T> inline void SharedData<T>::addRef () { + use_count++; + weak_count++; +#ifdef SHAREDPTR_DEBUG + std::cerr << "SharedData::addRef use:" << use_count << " weak:" << weak_count << std::endl; +#endif +} + +template <class T> inline void SharedData<T>::addWeakRef () { + weak_count++; +#ifdef SHAREDPTR_DEBUG + std::cerr << "SharedData::addWeakRef use:" << use_count << " weak:" << weak_count << std::endl; +#endif +} + +template <class T> inline void SharedData<T>::releaseWeak () { + ASSERT (weak_count > 0 && weak_count > use_count); +#ifdef SHAREDPTR_DEBUG + std::cerr << "SharedData::releaseWeak use:" << use_count << " weak:" << weak_count-1 << std::endl; +#endif + if (--weak_count <= 0) delete this; +} + +template <class T> inline void SharedData<T>::release () { + ASSERT (use_count > 0); + if (--use_count <= 0) dispose (); +#ifdef SHAREDPTR_DEBUG + std::cerr << "SharedData::release use:" << use_count << " weak:" << weak_count << std::endl; +#endif + releaseWeak (); +} + +template <class T> inline void SharedData<T>::dispose () { + ASSERT (use_count == 0); +#ifdef SHAREDPTR_DEBUG + std::cerr << "SharedData::dispose use:" << use_count << " weak:" << weak_count << std::endl; +#endif + delete ptr; + ptr = 0; +} + +template <class T> struct WeakPtr; + +/** + * Shared class based on boost shared + * This makes it possible to share pointers w/o having to worry about + * memory leaks. A pointer gets deleted as soon as the last Shared pointer + * gets destroyed. As such, never use (or be extremely carefull) not to + * use pointers or references to shared objects + **/ +template <class T> +struct SharedPtr { + SharedPtr () : data (0L) {}; + SharedPtr (T *t) : data (t ? new SharedData<T> (t, false) : 0L) {} + SharedPtr (const SharedPtr<T> & s) : data (s.data) { if (data) data->addRef (); } + SharedPtr (const WeakPtr <T> &); + ~SharedPtr () { if (data) data->release (); } + SharedPtr<T> & operator = (const SharedPtr<T> &); + SharedPtr<T> & operator = (const WeakPtr<T> &); + SharedPtr<T> & operator = (T *); + T * ptr () const { return data ? data->ptr : 0L; } + T * operator -> () { return data ? data->ptr : 0L; } + T * operator -> () const { return data ? data->ptr : 0L; } + T & operator * () { return *data->ptr; } + const T & operator * () const { return *data->ptr; } + // operator bool () const { return data && data->ptr; } + bool operator == (const SharedPtr<T> & s) const { return data == s.data; } + bool operator == (const WeakPtr<T> & w) const; + bool operator == (const T * t) const { return (!t && !data) || (data && data->ptr == t); } + bool operator == (T * t) const { return (!t && !data) || (data && data->ptr == t); } + bool operator != (const SharedPtr<T> & s) const { return data != s.data; } + bool operator != (const WeakPtr<T> & w) const; + bool operator != (const T * t) const { return !operator == (t); } + operator T * () { return data ? data->ptr : 0L; } + operator const T * () const { return data ? data->ptr : 0L; } + mutable SharedData<T> * data; +}; + +template <class T> +bool operator == (T * t, SharedPtr <T> & s) { + return (!t && !s.data) || (s.data && s.data->ptr == t); +} + +template <class T> +bool operator == (const T * t, SharedPtr <T> & s) { + return (!t && !s.data) || (s.data && s.data->ptr == t); +} + +template <class T> +inline SharedPtr<T> & SharedPtr<T>::operator = (const SharedPtr<T> & s) { + if (data != s.data) { + SharedData<T> * tmp = data; + data = s.data; + if (data) data->addRef (); + if (tmp) tmp->release (); + } + return *this; +} + +template <class T> inline SharedPtr<T> & SharedPtr<T>::operator = (T * t) { + if ((!data && t) || (data && data->ptr != t)) { + if (data) data->release (); + data = t ? new SharedData<T> (t, false) : 0L; + } + return *this; +} + +/** + * Weak version of SharedPtr. This will also have access to the SharedData + * pointer, only these object wont prevent destruction of the shared + * pointer, hence weak references + */ +template <class T> +struct WeakPtr { + WeakPtr () : data (0L) {}; + WeakPtr (T * t) : data (t ? new SharedData<T> (t, true) : 0) {} + WeakPtr (T * t, bool /*b*/) : data (t ? new SharedData<T> (t, true) : 0) {} + WeakPtr (const WeakPtr<T> & s) : data (s.data) { if (data) data->addWeakRef (); } + WeakPtr (const SharedPtr<T> & s) : data (s.data) { if (data) data->addWeakRef (); } + ~WeakPtr () { if (data) data->releaseWeak (); } + WeakPtr<T> & operator = (const WeakPtr<T> &); + WeakPtr<T> & operator = (const SharedPtr<T> &); + WeakPtr<T> & operator = (T *); + T * ptr () const { return data ? data->ptr : 0L; } + T * operator -> () { return data ? data->ptr : 0L; } + const T * operator -> () const { return data ? data->ptr : 0L; } + T & operator * () { return *data->ptr; } + const T & operator * () const { return *data->ptr; } + // operator bool () const { return data && !!data->ptr; } + bool operator == (const WeakPtr<T> & w) const { return data == w.data; } + bool operator == (const SharedPtr<T> & s) const { return data == s.data; } + bool operator == (const T * t) const { return (!t && !data) || (data && data.ptr == t); } + bool operator == (T * t) const { return (!t && !data) || (data && data.ptr == t); } + bool operator != (const WeakPtr<T> & w) const { return data != w.data; } + bool operator != (const SharedPtr<T> & s) const { return data != s.data; } + operator T * () { return data ? data->ptr : 0L; } + operator const T * () const { return data ? data->ptr : 0L; } + mutable SharedData<T> * data; +}; + +template <class T> +bool operator == (T * t, WeakPtr <T> & s) { + return (!t && !s.data) || (s.data && s.data->ptr == t); +} + +template <class T> +bool operator == (const T * t, WeakPtr <T> & s) { + return (!t && !s.data) || (s.data && s.data->ptr == t); +} + +template <class T> +inline WeakPtr<T> & WeakPtr<T>::operator = (const WeakPtr<T> & w) { + if (data != w.data) { + SharedData<T> * tmp = data; + data = w.data; + if (data) data->addWeakRef (); + if (tmp) tmp->releaseWeak (); + } + return *this; +} + +template <class T> +inline WeakPtr<T> & WeakPtr<T>::operator = (const SharedPtr<T> & s) { + if (data != s.data) { + SharedData<T> * tmp = data; + data = s.data; + if (data) data->addWeakRef (); + if (tmp) tmp->releaseWeak (); + } + return *this; +} + +template <class T> +inline WeakPtr<T> & WeakPtr<T>::operator = (T * t) { + if (data) data->releaseWeak (); + data = t ? new SharedData<T> (t, true) : 0L; + return *this; +} + +template <class T> inline SharedPtr<T>::SharedPtr (const WeakPtr <T> & w) : data (w.data) { + if (data) data->addRef (); +} + +template <class T> +inline SharedPtr<T> & SharedPtr<T>::operator = (const WeakPtr<T> & s) { + if (data != s.data) { + SharedData<T> * tmp = data; + data = s.data; + if (data) data->addRef (); + if (tmp) tmp->release (); + } + return *this; +} + +template <class T> +inline bool SharedPtr<T>::operator == (const WeakPtr<T> & w) const { + return data == w.data; +} + +template <class T> +inline bool SharedPtr<T>::operator != (const WeakPtr<T> & w) const { + return data != w.data; +} + +} + +#endif diff --git a/src/kmplayersource.h b/src/kmplayersource.h new file mode 100644 index 0000000..e93f98f --- /dev/null +++ b/src/kmplayersource.h @@ -0,0 +1,176 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2003 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KMPLAYERSOURCE_H +#define KMPLAYERSOURCE_H + +#include <qobject.h> +#include <qstring.h> +#include <kurl.h> + +#include "kmplayerplaylist.h" +#include "kmplayerprocess.h" + +class KConfig; +class QWidget; +class QFrame; + +namespace KMPlayer { + +class PartBase; + +/** + * Class for a certain media, like URL, DVD, TV etc + */ +class KMPLAYER_EXPORT Source : public QObject, public PlayListNotify { + Q_OBJECT +public: + Source (const QString & name, PartBase * player, const char * src); + virtual ~Source (); + virtual void init (); + virtual bool processOutput (const QString & line); + + bool identified () const { return m_identified; } + virtual bool hasLength (); + virtual bool isSeekable (); + + KDE_NO_EXPORT int width () const { return m_width; } + KDE_NO_EXPORT int height () const { return m_height; } + virtual void dimensions (int & w, int & h) { w = m_width; h = m_height; } + /* length () returns length in deci-seconds */ + KDE_NO_EXPORT int length () const { return m_length; } + /* position () returns position in deci-seconds */ + KDE_NO_EXPORT int position () const { return m_position; } + KDE_NO_EXPORT float aspect () const { return m_aspect; } + KDE_NO_EXPORT const KURL & url () const { return m_url; } + KDE_NO_EXPORT const KURL & subUrl () const { return m_sub_url; } + PartBase * player () { return m_player; } + virtual void reset (); + QString currentMrl (); + KDE_NO_EXPORT const QString & audioDevice () const { return m_audiodevice; } + KDE_NO_EXPORT const QString & videoDevice () const { return m_videodevice; } + KDE_NO_EXPORT const QString & videoNorm () const { return m_videonorm; } + /* frequency() if set, returns frequency in kHz */ + KDE_NO_EXPORT int frequency () const { return m_frequency; } + KDE_NO_EXPORT int xvPort () const { return m_xvport; } + KDE_NO_EXPORT int xvEncoding () const { return m_xvencoding; } + KDE_NO_EXPORT const QString & pipeCmd () const { return m_pipecmd; } + KDE_NO_EXPORT const QString & options () const { return m_options; } + KDE_NO_EXPORT const QString & recordCmd () const { return m_recordcmd; } + KDE_NO_EXPORT const QString & tuner () const { return m_tuner; } + KDE_NO_EXPORT NodePtr current () const { return m_current; } + QString plugin (const QString &mime) const; + virtual NodePtr document (); + virtual NodePtr root (); + virtual QString filterOptions (); + + virtual void setURL (const KURL & url); + void insertURL (NodePtr mrl, const QString & url, const QString & title=QString()); + KDE_NO_EXPORT void setSubURL (const KURL & url) { m_sub_url = url; } + void setLanguages (const QStringList & alang, const QStringList & slang); + KDE_NO_EXPORT void setWidth (int w) { m_width = w; } + KDE_NO_EXPORT void setHeight (int h) { m_height = h; } + virtual void setDimensions (NodePtr, int w, int h); + virtual void setAspect (NodePtr, float a); + /* setLength (len) set length in deci-seconds */ + void setLength (NodePtr, int len); + /* setPosition (pos) set position in deci-seconds */ + void setPosition (int pos); + virtual void setIdentified (bool b = true); + // backend process state changed + virtual void stateChange (Process *, Process::State os, Process::State ns); + KDE_NO_EXPORT void setAutoPlay (bool b) { m_auto_play = b; } + KDE_NO_EXPORT bool autoPlay () const { return m_auto_play; } + void setTitle (const QString & title); + void setLoading (int percentage); + bool setCurrent (NodePtr mrl); + + virtual QString prettyName (); +signals: + void startPlaying (); + void stopPlaying (); + void startRecording (); + void stopRecording (); + /** + * Signal for notifying this source is at the end of play items + */ + void endOfPlayItems (); + void dimensionsChanged (); + void titleChanged (const QString & title); +public slots: + virtual void activate () = 0; + virtual void deactivate () = 0; + virtual void forward (); + virtual void backward (); + virtual void play (); + /** + * Continuing playing where current is now + * May call play process if a video needs to play or + * emit endOfPlayItems when done + */ + virtual void playCurrent (); + virtual void jump (NodePtr e); + void setAudioLang (int); + void setSubtitle (int); +protected: + void timerEvent (QTimerEvent *); + /** + * PlayListNotify implementation + */ + bool requestPlayURL (NodePtr mrl); + bool resolveURL (NodePtr mrl); + void stateElementChanged (Node * element, Node::State os, Node::State ns); + SurfacePtr getSurface (NodePtr node); + void setInfoMessage (const QString & msg); + void bitRates (int & preferred, int & maximal); + void setTimeout (int ms); + + NodePtr m_document; + NodePtrW m_current; + NodePtrW m_back_request; + QString m_name; + PartBase * m_player; + QString m_recordcmd; + bool m_identified; + bool m_auto_play; + KURL m_url; + KURL m_sub_url; + QString m_audiodevice; + QString m_videodevice; + QString m_videonorm; + QString m_tuner; + int m_frequency; + int m_xvport; + int m_xvencoding; + QString m_pipecmd; + QString m_options; + QString m_plugin; +private: + int m_width; + int m_height; + float m_aspect; + int m_length; + int m_position; + int m_doc_timer; +}; + +} // namespace + +#endif diff --git a/src/kmplayertvsource.cpp b/src/kmplayertvsource.cpp new file mode 100644 index 0000000..8ccdcd6 --- /dev/null +++ b/src/kmplayertvsource.cpp @@ -0,0 +1,737 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2003 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qlayout.h> +#include <qlabel.h> +#include <qtimer.h> +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qtable.h> +#include <qstringlist.h> +#include <qcombobox.h> +#include <qlineedit.h> +#include <qgroupbox.h> +#include <qwhatsthis.h> +#include <qtabwidget.h> +#include <qmessagebox.h> +#include <qpopupmenu.h> +#include <qfontmetrics.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <klineedit.h> +#include <kurlrequester.h> +#include <kcombobox.h> +#include <kconfig.h> +#include <kstandarddirs.h> + +#include "kmplayerpartbase.h" +#include "kmplayerprocess.h" +#include "kmplayerconfig.h" +#include "kmplayertvsource.h" +#include "playlistview.h" +#include "kmplayer.h" +#include "kmplayercontrolpanel.h" +#include "kmplayerbroadcast.h" + +static const char * strTV = "TV"; +static const char * strTVDriver = "Driver"; + + +KDE_NO_CDTOR_EXPORT TVDevicePage::TVDevicePage (QWidget *parent, KMPlayer::NodePtr dev) +: QFrame (parent, "PageTVDevice"), device_doc (dev) { + TVDevice * device = KMPlayer::convertNode <TVDevice> (device_doc); + QVBoxLayout *layout = new QVBoxLayout (this, 5, 2); + QLabel * deviceLabel = new QLabel (i18n ("Video device:") + device->src, this, 0); + layout->addWidget (deviceLabel); + QGridLayout *gridlayout = new QGridLayout (layout, 3, 4); + QLabel * audioLabel = new QLabel (i18n ("Audio device:"), this); + audiodevice = new KURLRequester (device->getAttribute ("audio"), this); + QLabel * nameLabel = new QLabel (i18n ("Name:"), this, 0); + name = new QLineEdit (device->pretty_name, this, 0); + QLabel *sizewidthLabel = new QLabel (i18n ("Width:"), this, 0); + sizewidth = new QLineEdit (device->getAttribute (KMPlayer::StringPool::attr_width), this, 0); + QLabel *sizeheightLabel = new QLabel (i18n ("Height:"), this, 0); + sizeheight = new QLineEdit (device->getAttribute (KMPlayer::StringPool::attr_height), this, 0); + noplayback = new QCheckBox (i18n ("Do not immediately play"), this); + noplayback->setChecked (!device->getAttribute ("playback").toInt ()); + QWhatsThis::add (noplayback, i18n ("Only start playing after clicking the play button")); + inputsTab = new QTabWidget (this); + for (KMPlayer::NodePtr ip = device->firstChild (); ip; ip = ip->nextSibling ()) { + if (ip->id != id_node_tv_input) + continue; + TVInput * input = KMPlayer::convertNode <TVInput> (ip); + QWidget * widget = new QWidget (this); + QHBoxLayout *tablayout = new QHBoxLayout (widget, 5, 2); + if (!input->getAttribute ("tuner").isEmpty ()) { + QHBoxLayout *horzlayout = new QHBoxLayout (); + QVBoxLayout *vertlayout = new QVBoxLayout (); + horzlayout->addWidget (new QLabel (i18n ("Norm:"), widget)); + QComboBox * norms = new QComboBox (widget, "PageTVNorm"); + norms->insertItem (QString ("NTSC"), 0); + norms->insertItem (QString ("PAL"), 1); + norms->insertItem (QString ("SECAM"), 2); + norms->setCurrentText (input->getAttribute ("norm")); + horzlayout->addWidget (norms); + vertlayout->addLayout (horzlayout); + vertlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + QTable * table = new QTable (90, 2, widget, "PageTVChannels"); + QFontMetrics metrics (table->font ()); + QHeader *header = table->horizontalHeader(); + header->setLabel (0, i18n ("Channel")); + header->setLabel (1, i18n ("Frequency (MHz)")); + int index = 0; + int first_column_width = QFontMetrics (header->font ()).boundingRect (header->label (0)).width () + 20; + for (KMPlayer::NodePtr c=input->firstChild();c;c=c->nextSibling()) { + if (c->id != id_node_tv_channel) + continue; + int strwid = metrics.boundingRect (c->mrl ()->pretty_name).width (); + if (strwid > first_column_width) + first_column_width = strwid + 4; + table->setItem (index, 0, new QTableItem (table, QTableItem::Always, c->mrl ()->pretty_name)); + table->setItem (index++, 1, new QTableItem (table, QTableItem::Always, KMPlayer::convertNode<TVChannel>(c)->getAttribute ("frequency"))); + } + table->setColumnWidth (0, first_column_width); + table->setColumnStretchable (1, true); + tablayout->addWidget (table); + tablayout->addLayout (vertlayout); + } + inputsTab->addTab (widget, input->mrl ()->pretty_name); + } + QPushButton * delButton = new QPushButton (i18n ("Delete"), this); + connect (delButton, SIGNAL (clicked ()), this, SLOT (slotDelete ())); + gridlayout->addWidget (audioLabel, 0, 0); + gridlayout->addMultiCellWidget (audiodevice, 0, 0, 1, 3); + gridlayout->addWidget (nameLabel, 1, 0); + gridlayout->addMultiCellWidget (name, 1, 1, 1, 3); + gridlayout->addWidget (sizewidthLabel, 2, 0); + gridlayout->addWidget (sizewidth, 2, 1); + gridlayout->addWidget (sizeheightLabel, 2, 2); + gridlayout->addWidget (sizeheight, 2, 3); + layout->addWidget (inputsTab); + layout->addSpacing (5); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + QHBoxLayout *buttonlayout = new QHBoxLayout (); + buttonlayout->addWidget (noplayback); + buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + buttonlayout->addWidget (delButton); + layout->addLayout (buttonlayout); +} + +KDE_NO_EXPORT void TVDevicePage::slotDelete () { + if (KMessageBox::warningYesNo (this, i18n ("You are about to remove this device from the Source menu.\nContinue?"), i18n ("Confirm")) == KMessageBox::Yes) + emit deleted (this); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageTV::KMPlayerPrefSourcePageTV (QWidget *parent, KMPlayerTVSource * tvsource) +: QFrame (parent), m_tvsource (tvsource) { + QVBoxLayout * mainlayout = new QVBoxLayout (this, 5); + notebook = new QTabWidget (this); + notebook->setTabPosition (QTabWidget::Bottom); + mainlayout->addWidget (notebook); + QWidget * general = new QWidget (notebook); + QVBoxLayout *layout = new QVBoxLayout (general); + QGridLayout *gridlayout = new QGridLayout (layout, 2, 2, 2); + QLabel *driverLabel = new QLabel (i18n ("Driver:"), general, 0); + driver = new QLineEdit ("", general, 0); + QWhatsThis::add (driver, i18n ("dummy, v4l or bsdbt848")); + QLabel *deviceLabel = new QLabel (i18n ("Device:"), general, 0); + device = new KURLRequester ("/dev/video", general); + QWhatsThis::add(device, i18n("Path to your video device, eg. /dev/video0")); + scan = new QPushButton (i18n ("Scan..."), general); + gridlayout->addWidget (driverLabel, 0, 0); + gridlayout->addWidget (driver, 0, 1); + gridlayout->addWidget (deviceLabel, 1, 0); + gridlayout->addWidget (device, 1, 1); + QHBoxLayout *buttonlayout = new QHBoxLayout (); + buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + buttonlayout->addWidget (scan); + layout->addLayout (buttonlayout); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + notebook->insertTab (general, i18n ("General")); +} + +KDE_NO_EXPORT void KMPlayerPrefSourcePageTV::showEvent (QShowEvent *) { + m_tvsource->readXML (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT TVNode::TVNode (KMPlayer::NodePtr &d, const QString & s, const char * t, short id, const QString & n) : KMPlayer::GenericMrl (d, s, n, t) { + this->id = id; + editable = true; +} + +KDE_NO_EXPORT void TVNode::setNodeName (const QString & nn) { + pretty_name = nn; + setAttribute (KMPlayer::StringPool::attr_name, nn); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT TVChannel::TVChannel (KMPlayer::NodePtr & d, const QString & n, double freq) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel, n) { + setAttribute (KMPlayer::StringPool::attr_name, n); + setAttribute ("frequency", QString::number (freq, 'f', 2)); +} + +KDE_NO_CDTOR_EXPORT TVChannel::TVChannel (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel) { +} + +KDE_NO_EXPORT void TVChannel::closed () { + pretty_name = getAttribute (KMPlayer::StringPool::attr_name); +} + +//----------------------------------------------------------------------------- + +TVInput::TVInput (KMPlayer::NodePtr & d, const QString & n, int id) + : TVNode (d, QString ("tv://"), "input", id_node_tv_input, n) { + setAttribute (KMPlayer::StringPool::attr_name, n); + setAttribute (KMPlayer::StringPool::attr_id, QString::number (id)); +} + +KDE_NO_CDTOR_EXPORT TVInput::TVInput (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "input", id_node_tv_input) { +} + +KDE_NO_EXPORT KMPlayer::NodePtr TVInput::childFromTag (const QString & tag) { + // kdDebug () << nodeName () << " childFromTag " << tag << endl; + if (tag == QString::fromLatin1 ("channel")) { + return new TVChannel (m_doc); + } else + return 0L; +} + +KDE_NO_EXPORT void TVInput::closed () { + //pretty_name = getAttribute (KMPlayer::StringPool::attr_name); +} + +KDE_NO_EXPORT void TVInput::setNodeName (const QString & name) { + Node * p = parentNode ().ptr (); + QString nm (name); + if (p && p->id == id_node_tv_device) { + int pos = name.find (QString (" - ") + p->mrl ()->pretty_name); + if (pos > -1) + nm.truncate (pos); + } + pretty_name = nm + QString (" - ") + pretty_name; + TVNode::setNodeName (nm); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT TVDevice::TVDevice (KMPlayer::NodePtr & doc, const QString & d) : TVNode (doc, d, "device", id_node_tv_device), zombie (false) { + setAttribute ("path", d); +} + +KDE_NO_CDTOR_EXPORT TVDevice::TVDevice (KMPlayer::NodePtr & doc) + : TVNode (doc, i18n ("tv device"), "device", id_node_tv_device), zombie (false) { +} + +KDE_NO_CDTOR_EXPORT TVDevice::~TVDevice () { + if (device_page) + device_page->deleteLater (); +} + +KDE_NO_EXPORT KMPlayer::NodePtr TVDevice::childFromTag (const QString & tag) { + // kdDebug () << nodeName () << " childFromTag " << tag << endl; + if (tag == QString::fromLatin1 ("input")) + return new TVInput (m_doc); + return 0L; +} + +KDE_NO_EXPORT void TVDevice::closed () { + updateNodeName (); +} + +KDE_NO_EXPORT void TVDevice::childDone (KMPlayer::NodePtr) { + finish (); +} + +KDE_NO_EXPORT void TVDevice::setNodeName (const QString & name) { + TVNode::setNodeName (name); + updateNodeName (); +} + +KDE_NO_EXPORT void TVDevice::updateNodeName () { + pretty_name = getAttribute (KMPlayer::StringPool::attr_name); + src = getAttribute ("path"); + for (KMPlayer::NodePtr c = firstChild (); c; c = c->nextSibling ()) + if (c->id == id_node_tv_input) { + TVInput * i = static_cast <TVInput *> (c.ptr ()); + i->pretty_name = i->getAttribute (KMPlayer::StringPool::attr_name) + + QString (" - ") + pretty_name; + } +} + +KDE_NO_EXPORT void TVDevice::updateDevicePage () { + if (!device_page) + return; + pretty_name = device_page->name->text (); + setAttribute (KMPlayer::StringPool::attr_name, pretty_name); + setAttribute ("audio", device_page->audiodevice->lineEdit()->text ()); + setAttribute ("playback", device_page->noplayback->isChecked() ? "0" : "1"); + setAttribute (KMPlayer::StringPool::attr_width, device_page->sizewidth->text ()); + setAttribute (KMPlayer::StringPool::attr_height, device_page->sizeheight->text ()); + int i = 0; + for (KMPlayer::NodePtr ip = firstChild(); ip; ip=ip->nextSibling(),++i) { + if (ip->id != id_node_tv_input) + continue; + TVInput * input = KMPlayer::convertNode <TVInput> (ip); + bool ok; + if (input->getAttribute ("tuner").toInt (&ok) && ok) { + QWidget * widget = device_page->inputsTab->page (i); + QTable * table = static_cast <QTable *> (widget->child ("PageTVChannels", "QTable")); + if (table) { + input->clearChildren (); + for (int j = 0; j<table->numRows() && table->item (j, 1); ++j) { + input->appendChild (new TVChannel (m_doc, table->item (j, 0)->text (), table->item (j, 1)->text ().toDouble ())); + } + } + QComboBox * norms = static_cast <QComboBox *> (widget->child ("PageTVNorm", "QComboBox")); + if (norms) { + input->setAttribute ("norm", norms->currentText ()); + } + } + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +TVDocument::TVDocument (KMPlayerTVSource * source) + : FileDocument (id_node_tv_document, "tv://", source), m_source (source) { + pretty_name = i18n ("Television"); +} + +KDE_NO_EXPORT KMPlayer::NodePtr TVDocument::childFromTag (const QString & tag) { + // kdDebug () << nodeName () << " childFromTag " << tag << endl; + if (tag == QString::fromLatin1 ("device")) + return new TVDevice (m_doc); + return FileDocument::childFromTag (tag); +} + +KDE_NO_EXPORT void TVDocument::childDone (KMPlayer::NodePtr) { + finish (); +} + +KDE_NO_EXPORT void TVDocument::defer () { + if (!resolved) { + resolved = true; + readFromFile (locateLocal ("data", "kmplayer/tv.xml")); + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerTVSource::KMPlayerTVSource (KMPlayerApp * a, QPopupMenu * m) + : KMPlayerMenuSource (i18n ("TV"), a, m, "tvsource"), m_configpage (0L), scanner (0L), config_read (false) { + m_url = "tv://"; + m_menu->insertTearOffHandle (); + connect (m_menu, SIGNAL (aboutToShow ()), this, SLOT (menuAboutToShow ())); + m_document = new TVDocument (this); + m_player->settings ()->addPage (this); + tree_id = static_cast <KMPlayer::View*>(m_player->view ())->playList ()->addTree (m_document, "tvsource", "tv", KMPlayer::PlayListView::TreeEdit | KMPlayer::PlayListView::Moveable | KMPlayer::PlayListView::Deleteable); +} + +KDE_NO_CDTOR_EXPORT KMPlayerTVSource::~KMPlayerTVSource () { +} + +KDE_NO_EXPORT void KMPlayerTVSource::activate () { + m_identified = true; + if (m_player->settings ()->showbroadcastbutton) + m_app->view()->controlPanel()->broadcastButton ()->show (); + if (m_cur_tvdevice && !m_current) { + for (KMPlayer::NodePtr i = m_cur_tvdevice->firstChild(); i && !m_current; i=i->nextSibling()) + if (i->id == id_node_tv_input) { + TVInput * input = KMPlayer::convertNode <TVInput> (i); + bool ok; + m_cur_tvinput = i; + if (input->getAttribute ("tuner").toInt (&ok) && ok) { + for (KMPlayer::NodePtr c = i->firstChild (); c; c = c->nextSibling ()) + if (c->id == id_node_tv_channel) { + m_current = c; + break; + } + } else + m_current = i; + } + } else if (!m_cur_tvdevice) + KMPlayer::Source::reset (); + buildArguments (); + if (m_cur_tvdevice) { + QString playback = static_cast <KMPlayer::Element *> (m_cur_tvdevice.ptr ())->getAttribute (QString::fromLatin1 ("playback")); + if (playback.isEmpty () || playback.toInt ()) + QTimer::singleShot (0, m_player, SLOT (play ())); + } +} +/* TODO: playback by + * ffmpeg -vd /dev/video0 -r 25 -s 768x576 -f rawvideo - |mplayer -nocache -ao arts -rawvideo on:w=768:h=576:fps=25 -quiet - + */ + +KDE_NO_EXPORT void KMPlayerTVSource::deactivate () { + if (m_player->view () && !m_app->view ()->controlPanel()->broadcastButton ()->isOn ()) + m_app->view ()->controlPanel()->broadcastButton ()->hide (); + reset (); +} + +KDE_NO_EXPORT void KMPlayerTVSource::buildMenu () { + m_menu->clear (); + int counter = 0; + for (KMPlayer::NodePtr dp = m_document->firstChild (); dp; dp = dp->nextSibling ()) + if (dp->id == id_node_tv_device) + m_menu->insertItem (KMPlayer::convertNode <TVDevice> (dp)->pretty_name, this, SLOT (menuClicked (int)), 0, counter++); +} + +KDE_NO_EXPORT void KMPlayerTVSource::menuAboutToShow () { + readXML (); +} + +void KMPlayerTVSource::jump (KMPlayer::NodePtr e) { + if (e->id == id_node_tv_document) { + readXML (); + } else { + m_current = e; + for (; e; e = e->parentNode ()) { + if (e->id == id_node_tv_device) { + m_cur_tvdevice = e; + break; + } else if (e->id == id_node_tv_input) + m_cur_tvinput = e; + } + if (m_player->source () != this) + m_player->setSource (this); + else if (m_player->process ()->playing ()) { + m_back_request = m_current; + m_player->process ()->stop (); + } else + playCurrent (); + } +} + +KDE_NO_EXPORT KMPlayer::NodePtr KMPlayerTVSource::root () { + return m_cur_tvinput; +} + +KDE_NO_EXPORT void KMPlayerTVSource::buildArguments () { + TVChannel * channel = 0L; + TVInput * input = 0L; + KMPlayer::NodePtr elm = m_current; + if (elm && elm->id == id_node_tv_channel) { + channel = KMPlayer::convertNode <TVChannel> (elm); + elm = elm->parentNode (); + } + if (elm && elm->id == id_node_tv_input) + input = KMPlayer::convertNode <TVInput> (elm); + if (!(channel || (input && input->getAttribute ("tuner").isEmpty ()))) + return; + m_cur_tvinput = input; + m_cur_tvdevice = input->parentNode (); + static_cast <KMPlayer::View*>(m_player->view ())->playList ()->updateTree (0, m_cur_tvinput, m_current, true, false); + if (m_cur_tvdevice->id != id_node_tv_device) { + return; + } + TVDevice * tvdevice = KMPlayer::convertNode <TVDevice> (m_cur_tvdevice); + m_identified = true; + m_audiodevice = tvdevice->getAttribute ("audio"); + m_videodevice = tvdevice->src; + m_videonorm = input->getAttribute ("norm"); + m_tuner = input->getAttribute (KMPlayer::StringPool::attr_name); + QString xvport = tvdevice->getAttribute ("xvport"); + if (!xvport.isEmpty ()) + m_xvport = xvport.toInt (); + QString xvenc = input->getAttribute ("xvenc"); + if (!xvenc.isEmpty ()) + m_xvencoding = xvenc.toInt (); + QString command; + command.sprintf ("device=%s:input=%s", + tvdevice->src.ascii (), + input->getAttribute (KMPlayer::StringPool::attr_id).ascii ()); + if (channel) { + QString freq = channel->getAttribute ("frequency"); + m_frequency = (int)(1000 * freq.toDouble ()); + command += QString (":freq=%1").arg (freq); + } else + m_frequency = 0; + if (!m_videonorm.isEmpty ()) + command += QString (":norm=%1").arg (m_videonorm); + m_app->setCaption (i18n ("TV: ") + (channel ? channel->mrl ()->pretty_name : input->mrl ()->pretty_name), false); + setDimensions (m_cur_tvdevice, + tvdevice->getAttribute (KMPlayer::StringPool::attr_width).toInt (), + tvdevice->getAttribute (KMPlayer::StringPool::attr_height).toInt ()); + m_options.sprintf ("-tv noaudio:driver=%s:%s:width=%d:height=%d -slave -nocache -quiet", tvdriver.ascii (), command.ascii (), width (), height ()); + if (m_player->settings ()->mplayerpost090) + m_recordcmd.sprintf ("-tv %s:driver=%s:%s:width=%d:height=%d", m_audiodevice.isEmpty () ? "noaudio" : (QString ("forceaudio:adevice=") + m_audiodevice).ascii(), tvdriver.ascii (), command.ascii (), width (), height ()); + else + m_recordcmd.sprintf ("-tv on:%s:driver=%s:%s:width=%d:height=%d", m_audiodevice.isEmpty () ? "noaudio" : (QString ("forceaudio:adevice=") + m_audiodevice).ascii(), tvdriver.ascii (), command.ascii (), width (), height ()); +} + +KDE_NO_EXPORT void KMPlayerTVSource::playCurrent () { + buildArguments (); + if (m_app->broadcasting ()) + QTimer::singleShot (0, m_app->broadcastConfig (), SLOT (startFeed ())); + else + KMPlayer::Source::playCurrent (); +} + +KDE_NO_EXPORT void KMPlayerTVSource::menuClicked (int id) { + KMPlayer::NodePtr elm = m_document->firstChild (); + for (; id > 0; --id, elm = elm->nextSibling ()) + ; + m_cur_tvdevice = elm; + m_cur_tvinput = elm->firstChild (); // FIXME + m_current = 0L; + m_player->setSource (this); +} + +KDE_NO_EXPORT QString KMPlayerTVSource::filterOptions () { + if (! m_player->settings ()->disableppauto) + return KMPlayer::Source::filterOptions (); + return QString ("-vf pp=lb"); +} + +KDE_NO_EXPORT bool KMPlayerTVSource::hasLength () { + return false; +} + +KDE_NO_EXPORT bool KMPlayerTVSource::isSeekable () { + return true; +} + +KDE_NO_EXPORT QString KMPlayerTVSource::prettyName () { + QString name (i18n ("TV")); + //if (m_tvsource) + // name += ' ' + m_tvsource->title; + return name; +} + +KDE_NO_EXPORT void KMPlayerTVSource::write (KConfig * m_config) { + if (!config_read) return; + m_config->setGroup (strTV); + m_config->writeEntry (strTVDriver, tvdriver); + static_cast <TVDocument *> (m_document.ptr ())->writeToFile + (locateLocal ("data", "kmplayer/tv.xml")); + kdDebug () << "KMPlayerTVSource::write XML" << endl; +} + +KDE_NO_EXPORT void KMPlayerTVSource::readXML () { + if (config_read) return; + config_read = true; + kdDebug () << "KMPlayerTVSource::readXML" << endl; + m_document->defer (); + static_cast <KMPlayer::View*>(m_player->view ())->playList ()->updateTree (tree_id, m_document, 0, false, false); + buildMenu (); + sync (false); +} + +KDE_NO_EXPORT void KMPlayerTVSource::read (KConfig * m_config) { + m_config->setGroup (strTV); + tvdriver = m_config->readEntry (strTVDriver, "v4l"); +} + +KDE_NO_EXPORT void KMPlayerTVSource::sync (bool fromUI) { + if (!m_configpage) return; + if (m_document && m_document->hasChildNodes ()) + m_app->showBroadcastConfig (); + else + m_app->hideBroadcastConfig (); + if (fromUI) { + tvdriver = m_configpage->driver->text (); + for (KMPlayer::NodePtr d=m_document->firstChild();d; d=d->nextSibling()) + if (d->id == id_node_tv_device) + static_cast <TVDevice *> (d.ptr ())->updateDevicePage (); + } else { + m_configpage->driver->setText (tvdriver); + for (KMPlayer::NodePtr dp = m_document->firstChild (); dp; dp = dp->nextSibling ()) + if (dp->id == id_node_tv_device) + addTVDevicePage (KMPlayer::convertNode <TVDevice> (dp)); + } +} + +KDE_NO_EXPORT void KMPlayerTVSource::prefLocation (QString & item, QString & icon, QString & tab) { + item = i18n ("Source"); + icon = QString ("source"); + tab = i18n ("TV"); +} + +KDE_NO_EXPORT QFrame * KMPlayerTVSource::prefPage (QWidget * parent) { + if (!m_configpage) { + m_configpage = new KMPlayerPrefSourcePageTV (parent, this); + scanner = new TVDeviceScannerSource (this); + connect (m_configpage->scan, SIGNAL(clicked()), this, SLOT(slotScan())); + } + return m_configpage; +} + +static bool hasTVDevice (KMPlayer::NodePtr doc, const QString & devstr) { + for (KMPlayer::NodePtr e = doc->firstChild (); e; e = e->nextSibling ()) + if (e->id == id_node_tv_device && + KMPlayer::convertNode <TVDevice> (e)->src == devstr) + return true; + return false; +} + +KDE_NO_EXPORT void KMPlayerTVSource::slotScan () { + QString devstr = m_configpage->device->lineEdit()->text (); + if (!hasTVDevice(m_document, devstr)) { + scanner->scan (devstr, m_configpage->driver->text()); + connect (scanner, SIGNAL (scanFinished (TVDevice *)), + this, SLOT (slotScanFinished (TVDevice *))); + } else + KMessageBox::error (m_configpage, i18n ("Device already present."), + i18n ("Error")); +} + +KDE_NO_EXPORT void KMPlayerTVSource::slotScanFinished (TVDevice * tvdevice) { + disconnect (scanner, SIGNAL (scanFinished (TVDevice *)), + this, SLOT (slotScanFinished (TVDevice *))); + if (tvdevice) { + tvdevice->zombie = false; + addTVDevicePage (tvdevice, true); + } else + KMessageBox::error(m_configpage,i18n("No device found."),i18n("Error")); +} + +KDE_NO_EXPORT void KMPlayerTVSource::addTVDevicePage(TVDevice *dev, bool show) { + if (dev->device_page) + dev->device_page->deleteLater (); + dev->device_page = new TVDevicePage (m_configpage->notebook, dev); + m_configpage->notebook->insertTab (dev->device_page, dev->pretty_name); + connect (dev->device_page, SIGNAL (deleted (TVDevicePage *)), + this, SLOT (slotDeviceDeleted (TVDevicePage *))); + if (show) + m_configpage->notebook->setCurrentPage (m_configpage->notebook->count ()-1); +} + +KDE_NO_EXPORT void KMPlayerTVSource::slotDeviceDeleted (TVDevicePage *devpage) { + m_document->removeChild (devpage->device_doc); + m_configpage->notebook->setCurrentPage (0); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT TVDeviceScannerSource::TVDeviceScannerSource (KMPlayerTVSource * src) + : KMPlayer::Source (i18n ("TVScanner"), src->player (), "tvscanner"), m_tvsource (src), m_tvdevice (0L) { +} + +KDE_NO_EXPORT void TVDeviceScannerSource::init () { +} + +KDE_NO_EXPORT bool TVDeviceScannerSource::processOutput (const QString & line) { + if (m_nameRegExp.search (line) > -1) { + m_tvdevice->pretty_name = m_nameRegExp.cap (1); + m_tvdevice->setAttribute(KMPlayer::StringPool::attr_name,m_tvdevice->pretty_name); + kdDebug() << "Name " << m_tvdevice->pretty_name << endl; + } else if (m_sizesRegExp.search (line) > -1) { + m_tvdevice->setAttribute (KMPlayer::StringPool::attr_width, + m_sizesRegExp.cap(1)); + m_tvdevice->setAttribute (KMPlayer::StringPool::attr_height, + m_sizesRegExp.cap(2)); + m_tvdevice->setAttribute ("minwidth", m_sizesRegExp.cap (1)); + m_tvdevice->setAttribute ("minheight", m_sizesRegExp.cap (2)); + m_tvdevice->setAttribute ("maxwidth", m_sizesRegExp.cap (3)); + m_tvdevice->setAttribute ("maxheight", m_sizesRegExp.cap (4)); + } else if (m_inputRegExp.search (line) > -1) { + KMPlayer::NodePtr doc = m_tvsource->document (); + TVInput * input = new TVInput (doc, m_inputRegExp.cap (2).stripWhiteSpace (), + m_inputRegExp.cap (1).toInt ()); + if (m_inputRegExp.cap (3).toInt () == 1) + input->setAttribute ("tuner", "1"); + m_tvdevice->appendChild (input); + kdDebug() << "Input " << input->mrl ()->pretty_name << endl; + } else + return false; + return true; +} + +KDE_NO_EXPORT QString TVDeviceScannerSource::filterOptions () { + return QString (""); +} + +KDE_NO_EXPORT bool TVDeviceScannerSource::hasLength () { + return false; +} + +KDE_NO_EXPORT bool TVDeviceScannerSource::isSeekable () { + return false; +} + +KDE_NO_EXPORT bool TVDeviceScannerSource::scan (const QString & dev, const QString & dri) { + if (m_tvdevice) + return false; + setURL (KURL ("tv://")); + KMPlayer::NodePtr doc = m_tvsource->document (); + m_tvdevice = new TVDevice (doc, dev); + m_tvsource->document ()->appendChild (m_tvdevice); + m_tvdevice->zombie = true; // not for real yet + m_driver = dri; + m_old_source = m_tvsource->player ()->source (); + m_tvsource->player ()->setSource (this); + m_identified = true; + play (); + return true; +} + +KDE_NO_EXPORT void TVDeviceScannerSource::activate () { + m_nameRegExp.setPattern ("Selected device:\\s*([^\\s].*)"); + m_sizesRegExp.setPattern ("Supported sizes:\\s*([0-9]+)x([0-9]+) => ([0-9]+)x([0-9]+)"); + m_inputRegExp.setPattern ("\\s*([0-9]+):\\s*([^:]+):[^\\(]*\\(tuner:([01]),\\s*norm:([^\\)]+)\\)"); +} + +KDE_NO_EXPORT void TVDeviceScannerSource::deactivate () { + kdDebug () << "TVDeviceScannerSource::deactivate" << endl; + if (m_tvdevice) { + if (m_tvdevice->parentNode ()) + m_tvdevice->parentNode ()->removeChild (m_tvdevice); + m_tvdevice = 0L; + emit scanFinished (m_tvdevice); + } +} + +KDE_NO_EXPORT void TVDeviceScannerSource::play () { + if (!m_tvdevice) + return; + QString args; + args.sprintf ("tv:// -tv driver=%s:device=%s -identify -frames 0", m_driver.ascii (), m_tvdevice->src.ascii ()); + m_tvsource->player ()->stop (); + m_tvsource->player ()->process ()->initProcess (m_player->settings ()->defaultView ()->viewer ()); + KMPlayer::Process *proc = m_tvsource->player ()->players () ["mplayer"]; + proc->setSource (this); + if (!static_cast <KMPlayer::MPlayer *> (proc)->run (args.ascii())) + deactivate (); +} + +KDE_NO_EXPORT void TVDeviceScannerSource::stateChange (KMPlayer::Process * p, KMPlayer::Process::State os, KMPlayer::Process::State ns) { + if (m_tvdevice && // can be deactivated + ns == KMPlayer::Process::Ready && os > KMPlayer::Process::Ready) { + TVDevice * dev = 0L; + kdDebug () << "scanning done " << m_tvdevice->hasChildNodes () << endl; + if (!m_tvdevice->hasChildNodes ()) + m_tvsource->document ()->removeChild (m_tvdevice); + else + dev = m_tvdevice; + m_tvdevice = 0L; + m_player->setSource (m_old_source); + emit scanFinished (dev); + } + KMPlayer::Source::stateChange (p, os, ns); +} + +#include "kmplayertvsource.moc" diff --git a/src/kmplayertvsource.h b/src/kmplayertvsource.h new file mode 100644 index 0000000..ef5f416 --- /dev/null +++ b/src/kmplayertvsource.h @@ -0,0 +1,218 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2003 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KMPLAYER_TV_SOURCE_H_ +#define _KMPLAYER_TV_SOURCE_H_ + +#include <qguardedptr.h> +#include <qstring.h> +#include <qframe.h> + +#include "kmplayerappsource.h" +#include "kmplayerconfig.h" +#include "kmplayer.h" + +const short id_node_tv_document = 40; +const short id_node_tv_device = 41; +const short id_node_tv_input = 42; +const short id_node_tv_channel = 43; + +class KMPlayerPrefSourcePageTV; // source, TV +class TVDeviceScannerSource; +class KMPlayerTVSource; +class KURLRequester; +class KHistoryCombo; +class KMPlayerApp; +class QTabWidget; +class QGroupBox; +class QLineEdit; +class QCheckBox; +class KComboBox; +class KConfig; + + +class KMPLAYER_NO_EXPORT TVDevicePage : public QFrame { + Q_OBJECT +public: + TVDevicePage (QWidget *parent, KMPlayer::NodePtr dev); + KDE_NO_CDTOR_EXPORT ~TVDevicePage () {} + + QLineEdit * name; + KURLRequester * audiodevice; + QLineEdit * sizewidth; + QLineEdit * sizeheight; + QCheckBox * noplayback; + QTabWidget * inputsTab; + KMPlayer::NodePtrW device_doc; +signals: + void deleted (TVDevicePage *); +private slots: + void slotDelete (); +}; + +class KMPLAYER_NO_EXPORT KMPlayerPrefSourcePageTV : public QFrame { + Q_OBJECT +public: + KMPlayerPrefSourcePageTV (QWidget *parent, KMPlayerTVSource *); + KDE_NO_CDTOR_EXPORT ~KMPlayerPrefSourcePageTV () {} + QLineEdit * driver; + KURLRequester * device; + QPushButton * scan; + QTabWidget * notebook; +protected: + void showEvent (QShowEvent *); + KMPlayerTVSource * m_tvsource; +}; + +class KMPLAYER_NO_EXPORT TVNode : public KMPlayer::GenericMrl { +public: + TVNode (KMPlayer::NodePtr &d, const QString &s, const char * t, short id, const QString &n=QString ()); + virtual void setNodeName (const QString &); +}; + +/* + * Element for channels + */ +class KMPLAYER_NO_EXPORT TVChannel : public TVNode { +public: + TVChannel (KMPlayer::NodePtr & d, const QString & n, double f); + TVChannel (KMPlayer::NodePtr & d); + KDE_NO_CDTOR_EXPORT ~TVChannel () {} + void closed (); +}; + +/* + * Element for inputs + */ +class KMPLAYER_NO_EXPORT TVInput : public TVNode { +public: + TVInput (KMPlayer::NodePtr & d, const QString & n, int id); + TVInput (KMPlayer::NodePtr & d); + KDE_NO_CDTOR_EXPORT ~TVInput () {} + KMPlayer::NodePtr childFromTag (const QString &); + void setNodeName (const QString &); + void closed (); +}; + +/* + * Element for TV devices + */ +class KMPLAYER_NO_EXPORT TVDevice : public TVNode { +public: + TVDevice (KMPlayer::NodePtr & d, const QString & s); + TVDevice (KMPlayer::NodePtr & d); + ~TVDevice (); + KMPlayer::NodePtr childFromTag (const QString &); + void closed (); + void childDone (KMPlayer::NodePtr child); + void setNodeName (const QString &); + bool expose () const { return false; } + void updateNodeName (); + void updateDevicePage (); + bool zombie; + QGuardedPtr <TVDevicePage> device_page; +}; + +class KMPLAYER_NO_EXPORT TVDocument : public FileDocument { + KMPlayerTVSource * m_source; +public: + TVDocument (KMPlayerTVSource *); + KMPlayer::NodePtr childFromTag (const QString &); + void defer (); + KDE_NO_EXPORT const char * nodeName () const { return "tvdevices"; } + void childDone (KMPlayer::NodePtr child); +}; + + +/* + * Source form scanning TV devices + */ +class KMPLAYER_NO_EXPORT TVDeviceScannerSource : public KMPlayer::Source { + Q_OBJECT +public: + TVDeviceScannerSource (KMPlayerTVSource * src); + KDE_NO_CDTOR_EXPORT ~TVDeviceScannerSource () {}; + virtual void init (); + virtual bool processOutput (const QString & line); + virtual QString filterOptions (); + virtual bool hasLength (); + virtual bool isSeekable (); + virtual bool scan (const QString & device, const QString & driver); +public slots: + virtual void activate (); + virtual void deactivate (); + virtual void play (); + virtual void stateChange (KMPlayer::Process *, KMPlayer::Process::State os, KMPlayer::Process::State ns); +signals: + void scanFinished (TVDevice * tvdevice); +private: + KMPlayerTVSource * m_tvsource; + TVDevice * m_tvdevice; + KMPlayer::Source * m_old_source; + QString m_driver; + QRegExp m_nameRegExp; + QRegExp m_sizesRegExp; + QRegExp m_inputRegExp; +}; + +/* + * Source form TV devices, also implementing preference page for it + */ +class KMPLAYER_NO_EXPORT KMPlayerTVSource : public KMPlayerMenuSource, public KMPlayer::PreferencesPage { + Q_OBJECT +public: + KMPlayerTVSource (KMPlayerApp * app, QPopupMenu * m); + virtual ~KMPlayerTVSource (); + virtual QString filterOptions (); + virtual bool hasLength (); + virtual bool isSeekable (); + virtual KMPlayer::NodePtr root (); + void buildMenu (); + virtual QString prettyName (); + virtual void write (KConfig *); + virtual void read (KConfig *); + virtual void sync (bool); + virtual void prefLocation (QString & item, QString & icon, QString & tab); + virtual QFrame * prefPage (QWidget * parent); + void readXML (); +public slots: + virtual void activate (); + virtual void deactivate (); + virtual void playCurrent (); + virtual void jump (KMPlayer::NodePtr e); + void menuAboutToShow (); + void menuClicked (int id); +private slots: + void slotScan (); + void slotScanFinished (TVDevice * device); + void slotDeviceDeleted (TVDevicePage *); +private: + void addTVDevicePage (TVDevice * dev, bool show=false); + void buildArguments (); + KMPlayer::NodePtrW m_cur_tvdevice; + KMPlayer::NodePtrW m_cur_tvinput; + QPopupMenu * m_channelmenu; + QString tvdriver; + KMPlayerPrefSourcePageTV * m_configpage; + TVDeviceScannerSource * scanner; + int tree_id; + bool config_read; // whether tv.xml is read +}; + +#endif //_KMPLAYER_TV_SOURCE_H_ diff --git a/src/kmplayertypes.h b/src/kmplayertypes.h new file mode 100644 index 0000000..8b2e141 --- /dev/null +++ b/src/kmplayertypes.h @@ -0,0 +1,300 @@ +/* +* Copyright (C) 2006 Koos Vriezen <[email protected]> +* +* 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 +*/ + +#ifndef _KMPLAYER_TYPES_H_ +#define _KMPLAYER_TYPES_H_ + +#include <stdint.h> +#include "kmplayer_def.h" +#include "triestring.h" + +namespace KMPlayer { + +/** + * Type meant for screen coordinates + */ +class KMPLAYER_NO_EXPORT Single { + int value; + friend Single operator + (const Single s1, const Single s2); + friend Single operator - (const Single s1, const Single s2); + friend Single operator * (const Single s1, const Single s2); + friend Single operator / (const Single s1, const Single s2); + friend Single operator + (const Single s1, const int i); + friend Single operator - (const Single s1, const int i); + friend float operator * (const Single s, const float f); + friend double operator * (const Single s, const double f); + friend Single operator * (const int i, const Single s); + friend float operator * (const float f, const Single s); + friend double operator * (const double d, const Single s); + friend Single operator / (const Single s, const int i); + friend float operator / (const Single s, const float f); + friend double operator / (const Single s, const double d); + friend double operator / (const double d, const Single s); + friend bool operator > (const Single s1, const Single s2); + friend bool operator > (const Single s, const int i); + friend bool operator > (const int i, const Single s); + friend bool operator >= (const Single s1, const Single s2); + friend bool operator == (const Single s1, const Single s2); + friend bool operator != (const Single s1, const Single s2); + friend bool operator < (const Single s1, const Single s2); + friend bool operator < (const Single s, const int i); + friend bool operator < (const int i, const Single s); + friend bool operator <= (const Single s1, const Single s2); + friend bool operator <= (const Single s, const int i); +#ifdef _KDEBUG_H_ + friend kdbgstream & operator << (kdbgstream &, Single s); + friend kndbgstream & operator << (kndbgstream &, Single s); +#endif + friend Single operator - (const Single s); +public: + Single () : value (0) {} + Single (const int v) : value (v << 8) {} + Single (const float v) : value (int (256 * v)) {} + Single (const double v) : value (int (256 * v)) {} + Single & operator = (const Single s) { value = s.value; return *this; } + Single & operator = (const int v) { value = v << 8; return *this; } + Single & operator = (const float v) { value = int (256 * v); return *this; } + Single & operator = (const double v) { value = int(256 * v); return *this; } + Single & operator += (const Single s) { value += s.value; return *this; } + Single & operator += (const int i) { value += (i << 8); return *this; } + Single & operator -= (const Single s) { value -= s.value; return *this; } + Single & operator -= (const int i) { value -= (i << 8); return *this; } + Single & operator *= (const Single s); + Single & operator *= (const float f) { value = int(value*f); return *this; } + Single & operator /= (const int i) { value /= i; return *this; } + Single & operator /= (const float f); + operator int () const { return value >> 8; } + operator double () const { return 1.0 * value / 256; } +}; + +/** a b 0 + * Matrix for coordinate transforms c d 0 + * tx ty 1 */ +class KMPLAYER_NO_EXPORT Matrix { + friend class SizeEvent; + float a, b, c, d; + Single tx, ty; +public: + Matrix (); + Matrix (const Matrix & matrix); + Matrix (Single xoff, Single yoff, float xscale, float yscale); + void getXY (Single & x, Single & y) const; + void getXYWH (Single & x, Single & y, Single & w, Single & h) const; + void invXYWH (Single & x, Single & y, Single & w, Single & h) const; + void transform (const Matrix & matrix); + void scale (float sx, float sy); + void translate (Single x, Single y); + // void rotate (float phi); // add this when needed +}; + +class KMPLAYER_NO_EXPORT SRect { + Single _x, _y, _w, _h; +#ifdef _KDEBUG_H_ + friend kdbgstream & operator << (kdbgstream &, const SRect &s); + friend kndbgstream & operator << (kndbgstream &, const SRect &s); +#endif +public: + SRect () {} + SRect (Single a, Single b, Single w, Single h) + : _x (a), _y (b), _w (w), _h (h) {} + Single x () const { return _x; } + Single y () const { return _y; } + Single width () const { return _w; } + Single height () const { return _h; } + SRect unite (const SRect & r) const; + SRect intersect (const SRect & r) const; + bool isValid () const { return _w >= Single (0) && _h >= Single (0); } + bool operator == (const SRect & r) const; + bool operator != (const SRect & r) const; +}; + +class KMPLAYER_NO_EXPORT IRect { +public: + int x, y, w, h; + IRect () + : x (0), y (0), w (0), h (0) {} + explicit IRect (const SRect r) + : x (r.x ()), y (r.y ()), w (r.width ()), h (r.height ()) {} + IRect (int a, int b, int c, int d) + : x (a), y (b), w (c), h (d) {} + IRect unite (const IRect & r) const; + IRect intersect (const IRect & r) const; + bool isValid () const { return w >= 0 && h >= 0; } + bool isEmpty () const { return w < 0 || h < 0; } +}; + +//----------------------------------------------------------------------------- + +#ifdef _KDEBUG_H_ +inline kdbgstream & operator << (kdbgstream & dbg, Single s) { + dbg << (double) (s); + return dbg; +} + +inline kndbgstream & operator << (kndbgstream & dbg, Single) { return dbg; } + +inline kdbgstream & operator << (kdbgstream & dbg, const SRect &r) { + dbg << "SRect(x=" << r._x << " y=" << r._y << " w=" << r._w << " h=" << r._h << ")"; + return dbg; +} + +inline kndbgstream & operator << (kndbgstream &d, const SRect&) { return d; } + +inline kdbgstream & operator << (kdbgstream & dbg, const IRect &r) { + dbg << "IRect(x=" << r.x << " y=" << r.y << " w=" << r.w << " h=" << r.h << ")"; + return dbg; +} + +inline kndbgstream & operator << (kndbgstream &d, const IRect&) { return d; } +#endif + +inline Single & Single::operator *= (const Single s) { + value = (((int64_t)value) * s.value) >> 8; + return *this; +} + +inline Single & Single::operator /= (const float f) { + value = (int) (value / f); + return *this; +} + +inline Single operator + (const Single s1, const Single s2) { + Single s; + s.value = s1.value + s2.value; + return s; +} + +inline Single operator - (const Single s1, const Single s2) { + Single s; + s.value = s1.value - s2.value; + return s; +} + +inline Single operator * (const Single s1, const Single s2) { + Single s; + s.value = (((int64_t)s1.value) * s2.value) >> 8; + return s; +} + +inline Single operator / (const Single s1, const Single s2) { + Single s; + s.value = ((int64_t)s1.value << 8) / s2.value; + return s; +} + +inline Single operator + (const Single s, const int i) { + return s + Single (i); +} + +inline Single operator - (const Single s, const int i) { + return s - Single (i); +} + +inline Single operator * (const int i, const Single s) { + Single s1; + s1.value = s.value * i; + return s1; +} + +inline Single operator * (const Single s, const int i) { + return i * s; +} +inline float operator * (const Single s, const float f) { + return s.value * f / 256; +} + +inline double operator * (const Single s, const double d) { + return s.value * d / 256; +} + +inline float operator * (const float f, const Single s) { + return s.value * f / 256; +} + +inline double operator * (const double d, const Single s) { + return s.value * d / 256; +} + +inline Single operator / (const Single s, const int i) { + Single s1; + s1.value = s.value / i; + return s1; +} + +inline float operator / (const Single s, const float f) { + return (s.value / f ) / 256; +} + +inline double operator / (const Single s, const double d) { + return (s.value / d ) / 256; +} + +inline double operator / (const double d, const Single s) { + return (d * 256 / s.value); +} + +inline bool +operator > (const Single s1, const Single s2) { return s1.value > s2.value; } + +inline bool +operator > (const Single s, const int i) { return s > Single (i); } + +inline bool +operator > (const int i, const Single s) { return Single (i) > s; } + +inline bool +operator >= (const Single s1, const Single s2) { return s1.value >= s2.value; } + +inline bool +operator == (const Single s1, const Single s2) { return s1.value == s2.value; } + +inline bool +operator != (const Single s1, const Single s2) { return s1.value != s2.value; } + +inline bool +operator < (const Single s1, const Single s2) { return s1.value < s2.value; } + +inline bool +operator < (const Single s, const int i) { return s < Single (i); } + +inline bool +operator < (const int i, const Single s) { return Single (i) < s; } + +inline bool +operator <= (const Single s1, const Single s2) { return s1.value <= s2.value; } + +inline bool +operator <= (const Single s, const int i) { return s <= Single (i); } + +inline Single operator - (const Single s) { + Single s1; + s1.value = -s.value; + return s1; +} + +//----------------------------------------------------------------------------- + +inline bool SRect::operator == (const SRect & r) const { + return _x == r._x && _y == r._y && _w == r._w && _h == r._h; +} + +inline bool SRect::operator != (const SRect & r) const { return !(*this == r); } + +} // KMPlayer namespace + +#endif //_KMPLAYER_TYPES_H_ diff --git a/src/kmplayerui.rc b/src/kmplayerui.rc new file mode 100644 index 0000000..c726c4c --- /dev/null +++ b/src/kmplayerui.rc @@ -0,0 +1,99 @@ +<!DOCTYPE kpartgui> +<kpartgui name="kmplayer" version="24"> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="open"/> + <Action name="new_window"/> + <Action name="open_recent"/> + <Action name="save_as"/> + <Action name="clear_history"/> + <Separator/> + <Action name="source_pipe"/> + <Menu name="vdr"><text>VD&R</text> + <Action name="vdr_connect"/> + <Action name="vdr_key_up"/> + <Action name="vdr_key_down"/> + <Action name="vdr_key_back"/> + <Action name="vdr_key_ok"/> + <Action name="vdr_key_setup"/> + <Action name="vdr_key_channels"/> + <Action name="vdr_key_menu"/> + <Action name="vdr_key_red"/> + <Action name="vdr_key_green"/> + <Action name="vdr_key_yellow"/> + <Action name="vdr_key_blue"/> + <Action name="vdr_key_custom"/> + </Menu> + </Menu> + <Menu name="view"><text>&View</text> + <Action name="view_video"/> + <Action name="view_playlist"/> + <Action name="view_minimal"/> + <Action name="view_fullscreen"/> + <Menu name="zoom"><text>&Zoom</text> + <Action name="view_zoom_50"/> + <Action name="view_zoom_100"/> + <Action name="view_zoom_150"/> + </Menu> + <Action name="view_keep_ratio"/> + <Separator /> + <Action name="play"/> + <Action name="pause"/> + <Action name="stop"/> + <Separator /> + <Action name="find"/> + <Action name="next"/> + <Separator /> + <Action name="edit_mode"/> + <Action name="sync_edit_mode"/> + <Action name="edit_playlist_item"/> + <Separator /> + <Action name="view_arts_control"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Separator /> + <Action name="showmenu"/> + <Action name="showtoolbar"/> + <Action name="showstatusbar"/> + <Separator /> + <Action name="configkeys"/> + <Action name="configtoolbars"/> + <Action name="configure"/> + </Menu> +</MenuBar> +<ActionProperties> + <Action name="new_window" icon="window_new"/> + <Action name="play" icon="player_play"/> + <Action name="pause" icon="player_pause"/> + <Action name="stop" icon="player_stop"/> + <Action shortcut="F" name="view_fullscreen" /> + <Action shortcut="R" name="play" /> + <Action shortcut="P" name="pause" /> + <Action shortcut="S" name="stop" /> + <Action shortcut="F2" name="edit_playlist_item"/> + <Action shortcut="C" name="view_arts_control" /> +</ActionProperties> +<ToolBar name="mainToolBar"><text></text> + <Action name="new_window"/> + <Action name="open"/> + <Separator/> + <Action name="play"/> + <Action name="pause"/> + <Action name="stop"/> + <Separator/> + <Action name="view_fullscreen"/> + <Action name="view_zoom_100"/> + <Separator/> + <Action name="view_video"/> + <Action name="view_playlist"/> + <Action name="sync_edit_mode"/> + <Separator/> + <Action name="configure"/> + <Separator/> + <Action name="vdr_key_up"/> + <Action name="vdr_key_down"/> + <Action name="vdr_key_back"/> + <Action name="vdr_key_ok"/> + <Action name="vdr_key_menu"/> +</ToolBar> +</kpartgui> diff --git a/src/kmplayervdr.cpp b/src/kmplayervdr.cpp new file mode 100644 index 0000000..14a57ec --- /dev/null +++ b/src/kmplayervdr.cpp @@ -0,0 +1,780 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <math.h> +#include <unistd.h> + +#include <qlayout.h> +#include <qlabel.h> +#include <qmap.h> +#include <qtimer.h> +#include <qpushbutton.h> +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qtable.h> +#include <qstringlist.h> +#include <qcombobox.h> +#include <qlineedit.h> +#include <qgroupbox.h> +#include <qwhatsthis.h> +#include <qtabwidget.h> +#include <qradiobutton.h> +#include <qmessagebox.h> +#include <qpopupmenu.h> +#include <qsocket.h> +#include <qeventloop.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <klineedit.h> +#include <kurlrequester.h> +#include <kcombobox.h> +#include <kstatusbar.h> +#include <kprocess.h> +#include <kconfig.h> +#include <kaction.h> +#include <kiconloader.h> +#include <klistview.h> +#include <kdeversion.h> +#if KDE_IS_VERSION(3, 1, 90) +#include <kinputdialog.h> +#endif + +#include "kmplayer_backend_stub.h" +#include "kmplayer_callback.h" +#include "kmplayerpartbase.h" +#include "kmplayercontrolpanel.h" +#include "kmplayerconfig.h" +#include "playlistview.h" +#include "viewarea.h" +#include "kmplayervdr.h" +#include "kmplayer.h" + +using namespace KMPlayer; + +static const char * strVDR = "VDR"; +static const char * strVDRPort = "Port"; +static const char * strXVPort = "XV Port"; +static const char * strXVEncoding = "XV Encoding"; +static const char * strXVScale = "XV Scale"; + +KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageVDR::KMPlayerPrefSourcePageVDR (QWidget * parent, KMPlayer::PartBase * player) + : QFrame (parent), m_player (player) { + //KURLRequester * v4ldevice; + QVBoxLayout *layout = new QVBoxLayout (this, 5, 2); + QGridLayout *gridlayout = new QGridLayout (1, 2); + xv_port = new KListView (this); + xv_port->addColumn (QString()); + xv_port->header()->hide (); + xv_port->setTreeStepSize (15); + //xv_port->setRootIsDecorated (true); + //xv_port->setSorting (-1); + QListViewItem * vitem = new QListViewItem (xv_port, i18n ("XVideo port")); + vitem->setOpen (true); + QWhatsThis::add (xv_port, i18n ("Port base of the X Video extension.\nIf left to default (0), the first available port will be used. However if you have multiple XVideo instances, you might have to provide the port to use here.\nSee the output from 'xvinfo' for more information")); + QLabel * label = new QLabel (i18n ("Communication port:"), this); + gridlayout->addWidget (label, 0, 0); + tcp_port = new QLineEdit ("", this); + QWhatsThis::add (tcp_port, i18n ("Communication port with VDR. Default is port 2001.\nIf you use another port, with the '-p' option of 'vdr', you must set it here too.")); + gridlayout->addWidget (tcp_port, 0, 1); + layout->addWidget (xv_port); + layout->addLayout (gridlayout); + scale = new QButtonGroup (2, Qt::Vertical, i18n ("Scale"), this); + new QRadioButton (i18n ("4:3"), scale); + new QRadioButton (i18n ("16:9"), scale); + QWhatsThis::add (scale, i18n ("Aspects to use when viewing VDR")); + scale->setButton (0); + layout->addWidget (scale); + layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageVDR::~KMPlayerPrefSourcePageVDR () {} + +KDE_NO_EXPORT void KMPlayerPrefSourcePageVDR::showEvent (QShowEvent *) { + XVideo * xvideo = static_cast<XVideo *>(m_player->players()["xvideo"]); + if (!xvideo->configDocument ()) + xvideo->getConfigData (); +} +//----------------------------------------------------------------------------- + +static const char * cmd_chan_query = "CHAN\n"; +static const char * cmd_list_channels = "LSTC\n"; +static const char * cmd_volume_query = "VOLU\n"; + +class VDRCommand { +public: + KDE_NO_CDTOR_EXPORT VDRCommand (const char * c, VDRCommand * n=0L) + : command (strdup (c)), next (n) {} + KDE_NO_CDTOR_EXPORT ~VDRCommand () { free (command); } + char * command; + VDRCommand * next; +}; + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT KMPlayerVDRSource::KMPlayerVDRSource (KMPlayerApp * app) + : KMPlayer::Source (QString ("VDR"), app->player (), "vdrsource"), + m_app (app), + m_configpage (0), + m_socket (new QSocket (this)), + commands (0L), + channel_timer (0), + timeout_timer (0), + finish_timer (0), + tcp_port (0), + m_stored_volume (0) { + memset (m_actions, 0, sizeof (KAction *) * int (act_last)); + m_player->settings ()->addPage (this); + connect (m_socket, SIGNAL (connectionClosed()), this, SLOT(disconnected())); + connect (m_socket, SIGNAL (connected ()), this, SLOT (connected ())); + connect (m_socket, SIGNAL (readyRead ()), this, SLOT (readyRead ())); + connect (m_socket, SIGNAL (error (int)), this, SLOT (socketError (int))); +} + +KDE_NO_CDTOR_EXPORT KMPlayerVDRSource::~KMPlayerVDRSource () {} + +KDE_NO_CDTOR_EXPORT void KMPlayerVDRSource::waitForConnectionClose () { + if (timeout_timer) { + finish_timer = startTimer (500); + kdDebug () << "VDR connection not yet closed" << endl; + QApplication::eventLoop ()->enterLoop (); + kdDebug () << "VDR connection:" << (m_socket->state () == QSocket::Connected) << endl; + timeout_timer = 0; + } +} + +KDE_NO_EXPORT bool KMPlayerVDRSource::hasLength () { + return false; +} + +KDE_NO_EXPORT bool KMPlayerVDRSource::isSeekable () { + return true; +} + +KDE_NO_EXPORT QString KMPlayerVDRSource::prettyName () { + return i18n ("VDR"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::activate () { + last_channel = 0; + connect (this, SIGNAL (startPlaying ()), this, SLOT (processStarted())); + connect (this, SIGNAL (stopPlaying ()), this, SLOT (processStopped ())); + KMPlayer::ControlPanel * panel = m_app->view()->controlPanel (); + panel->button (KMPlayer::ControlPanel::button_red)->show (); + panel->button (KMPlayer::ControlPanel::button_green)->show (); + panel->button (KMPlayer::ControlPanel::button_yellow)->show (); + panel->button (KMPlayer::ControlPanel::button_blue)->show (); + panel->button (KMPlayer::ControlPanel::button_pause)->hide (); + panel->button (KMPlayer::ControlPanel::button_record)->hide (); + connect (panel->volumeBar (), SIGNAL (volumeChanged (int)), this, SLOT (volumeChanged (int))); + connect (panel->button (KMPlayer::ControlPanel::button_red), SIGNAL (clicked ()), this, SLOT (keyRed ())); + connect (panel->button (KMPlayer::ControlPanel::button_green), SIGNAL (clicked ()), this, SLOT (keyGreen ())); + connect (panel->button (KMPlayer::ControlPanel::button_yellow), SIGNAL (clicked ()), this, SLOT (keyYellow ())); + connect (panel->button (KMPlayer::ControlPanel::button_blue), SIGNAL (clicked ()), this, SLOT (keyBlue ())); + setAspect (m_document, scale ? 16.0/9 : 1.33); + if (!m_url.protocol ().compare ("kmplayer")) + m_request_jump = KURL::decode_string (m_url.path ()).mid (1); + setURL (KURL (QString ("vdr://localhost:%1").arg (tcp_port))); + QTimer::singleShot (0, m_player, SLOT (play ())); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::deactivate () { + disconnect (m_socket, SIGNAL (error (int)), this, SLOT (socketError (int))); + if (m_player->view ()) { + disconnect (this, SIGNAL(startPlaying()), this, SLOT(processStarted())); + disconnect (this, SIGNAL (stopPlaying()), this, SLOT(processStopped())); + KMPlayer::ControlPanel * panel = m_app->view()->controlPanel (); + disconnect (panel->volumeBar (), SIGNAL (volumeChanged (int)), this, SLOT (volumeChanged (int))); + disconnect (panel->button (KMPlayer::ControlPanel::button_red), SIGNAL (clicked ()), this, SLOT (keyRed ())); + disconnect (panel->button (KMPlayer::ControlPanel::button_green), SIGNAL (clicked ()), this, SLOT (keyGreen ())); + disconnect (panel->button (KMPlayer::ControlPanel::button_yellow), SIGNAL (clicked ()), this, SLOT (keyYellow ())); + disconnect (panel->button (KMPlayer::ControlPanel::button_blue), SIGNAL (clicked ()), this, SLOT (keyBlue ())); + } + processStopped (); + m_request_jump.truncate (0); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::playCurrent () { + if (m_player->process ()) + m_player->process ()->play (this, current ()); // FIXME HACK +} + +KDE_NO_EXPORT void KMPlayerVDRSource::processStopped () { + if (m_socket->state () == QSocket::Connected) { + queueCommand (QString ("VOLU %1\n").arg (m_stored_volume).ascii ()); + queueCommand ("QUIT\n"); + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::processStarted () { + m_socket->connectToHost ("127.0.0.1", tcp_port); + commands = new VDRCommand ("connect", commands); +} + +#define DEF_ACT(i,text,pix,scut,slot,name) \ + m_actions [i] = new KAction (text, QString (pix), KShortcut (scut), this, slot, m_app->actionCollection (), name); \ + m_fullscreen_actions [i] = new KAction (text, KShortcut (scut), this, slot, m_app->view ()->viewArea ()->actionCollection (), name) + +KDE_NO_EXPORT void KMPlayerVDRSource::connected () { + queueCommand (cmd_list_channels); + queueCommand (cmd_volume_query); + killTimer (channel_timer); + channel_timer = startTimer (3000); + KAction * action = m_app->actionCollection ()->action ("vdr_connect"); + action->setIcon (QString ("connect_no")); + action->setText (i18n ("Dis&connect")); + DEF_ACT (act_up, i18n ("VDR Key Up"), "up", , SLOT (keyUp ()), "vdr_key_up"); + DEF_ACT (act_down, i18n ("VDR Key Down"), "down", , SLOT (keyDown ()), "vdr_key_down"); + DEF_ACT (act_back, i18n ("VDR Key Back"), "back", , SLOT (keyBack ()), "vdr_key_back"); + DEF_ACT (act_ok, i18n ("VDR Key Ok"), "ok", , SLOT (keyOk ()), "vdr_key_ok"); + DEF_ACT (act_setup, i18n ("VDR Key Setup"), "configure", , SLOT (keySetup ()), "vdr_key_setup"); + DEF_ACT (act_channels, i18n ("VDR Key Channels"), "player_playlist", , SLOT (keyChannels ()), "vdr_key_channels"); + DEF_ACT (act_menu, i18n ("VDR Key Menu"), "showmenu", , SLOT (keyMenu ()), "vdr_key_menu"); + DEF_ACT (act_red, i18n ("VDR Key Red"), "red", , SLOT (keyRed ()), "vdr_key_red"); + DEF_ACT (act_green, i18n ("VDR Key Green"), "green", , SLOT (keyGreen ()), "vdr_key_green"); + DEF_ACT (act_yellow, i18n ("VDR Key Yellow"), "yellow", , SLOT (keyYellow ()), "vdr_key_yellow"); + DEF_ACT (act_blue, i18n ("VDR Key Blue"), "blue", , SLOT (keyBlue ()), "vdr_key_blue"); +#if KDE_IS_VERSION(3, 1, 90) + DEF_ACT (act_custom, "VDR Custom Command", "exec", , SLOT (customCmd ()), "vdr_key_custom"); +#endif + m_app->initMenu (); // update menu and toolbar + DEF_ACT (act_0, i18n ("VDR Key 0"), "0", Qt::Key_0, SLOT (key0 ()), "vdr_key_0"); + DEF_ACT (act_1, i18n ("VDR Key 1"), "1", Qt::Key_1, SLOT (key1 ()), "vdr_key_1"); + DEF_ACT (act_2, i18n ("VDR Key 2"), "2", Qt::Key_2, SLOT (key2 ()), "vdr_key_2"); + DEF_ACT (act_3, i18n ("VDR Key 3"), "3", Qt::Key_3, SLOT (key3 ()), "vdr_key_3"); + DEF_ACT (act_4, i18n ("VDR Key 4"), "4", Qt::Key_4, SLOT (key4 ()), "vdr_key_4"); + DEF_ACT (act_5, i18n ("VDR Key 5"), "5", Qt::Key_5, SLOT (key5 ()), "vdr_key_5"); + DEF_ACT (act_6, i18n ("VDR Key 6"), "6", Qt::Key_6, SLOT (key6 ()), "vdr_key_6"); + DEF_ACT (act_7, i18n ("VDR Key 7"), "7", Qt::Key_7, SLOT (key7 ()), "vdr_key_7"); + DEF_ACT (act_8, i18n ("VDR Key 8"), "8", Qt::Key_8, SLOT (key8 ()), "vdr_key_8"); + DEF_ACT (act_9, i18n ("VDR Key 9"), "9", Qt::Key_9, SLOT (key9 ()), "vdr_key_9"); + //KMPlayer::ViewLayer * layer = m_app->view ()->viewArea (); + for (int i = 0; i < int (act_last); ++i) + // somehow, the configured shortcuts only show up after createGUI() call + m_fullscreen_actions [i]->setShortcut (m_actions [i]->shortcut ()); + // m_fullscreen_actions[i]->plug (layer); +} + +#undef DEF_ACT + +KDE_NO_EXPORT void KMPlayerVDRSource::disconnected () { + kdDebug() << "disconnected " << commands << endl; + if (finish_timer) { + deleteCommands (); + return; + } + setURL (KURL (QString ("vdr://localhost:%1").arg (tcp_port))); + if (channel_timer && m_player->source () == this) + m_player->process ()->quit (); + deleteCommands (); + KAction * action = m_app->actionCollection ()->action ("vdr_connect"); + action->setIcon (QString ("connect_established")); + action->setText (i18n ("&Connect")); + m_app->guiFactory ()->removeClient (m_app);// crash w/ m_actions[i]->unplugAll (); in for loop below + for (int i = 0; i < int (act_last); ++i) + if (m_player->view () && m_actions[i]) { + m_fullscreen_actions[i]->unplug (m_app->view()->viewArea()); + delete m_actions[i]; + delete m_fullscreen_actions[i]; + } + m_app->initMenu (); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::toggleConnected () { + if (m_socket->state () == QSocket::Connected) { + queueCommand ("QUIT\n"); + killTimer (channel_timer); + channel_timer = 0; + } else { + m_socket->connectToHost ("127.0.0.1", tcp_port); + commands = new VDRCommand ("connect", commands); + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::volumeChanged (int val) { + queueCommand (QString ("VOLU %1\n").arg (int (sqrt (255 * 255 * val / 100))).ascii ()); +} + +static struct ReadBuf { + char * buf; + int length; + KDE_NO_CDTOR_EXPORT ReadBuf () : buf (0L), length (0) {} + KDE_NO_CDTOR_EXPORT ~ReadBuf () { + clear (); + } + KDE_NO_EXPORT void operator += (const char * s) { + int l = strlen (s); + char * b = new char [length + l + 1]; + if (length) + strcpy (b, buf); + strcpy (b + length, s); + length += l; + delete buf; + buf = b; + } + KDE_NO_EXPORT QCString mid (int p) { + return QCString (buf + p); + } + KDE_NO_EXPORT QCString left (int p) { + return QCString (buf, p); + } + KDE_NO_EXPORT QCString getReadLine (); + KDE_NO_EXPORT void clear () { + delete [] buf; + buf = 0; + length = 0; + } +} readbuf; + +KDE_NO_EXPORT QCString ReadBuf::getReadLine () { + QCString out; + if (!length) + return out; + int p = strcspn (buf, "\r\n"); + if (p < length) { + int skip = strspn (buf + p, "\r\n"); + out = left (p+1); + int nl = length - p - skip; + memmove (buf, buf + p + skip, nl + 1); + length = nl; + } + return out; +} + +KDE_NO_EXPORT void KMPlayerVDRSource::readyRead () { + KMPlayer::View * v = finish_timer ? 0L : static_cast <KMPlayer::View *> (m_player->view ()); + long nr = m_socket->bytesAvailable(); + char * data = new char [nr + 1]; + m_socket->readBlock (data, nr); + data [nr] = 0; + readbuf += data; + QCString line = readbuf.getReadLine (); + if (commands) { + bool cmd_done = false; + while (!line.isEmpty ()) { + bool toconsole = true; + cmd_done = (line.length () > 3 && line[3] == ' '); // from svdrpsend.pl + // kdDebug () << "readyRead " << cmd_done << " " << commands->command << endl; + if (!strcmp (commands->command, cmd_list_channels) && m_document) { + int p = line.find (';'); + int q = line.find (':'); + if (q > 0 && (p < 0 || q < p)) + p = q; + if (p > 0) + line.truncate (p); + QString channel_name = line.mid (4); + m_document->appendChild (new KMPlayer::GenericMrl (m_document, QString ("kmplayer://vdrsource/%1").arg(channel_name), channel_name)); + if (cmd_done) { + m_player->updateTree (); + if (!m_request_jump.isEmpty ()) { + jump (m_request_jump); + m_request_jump.truncate (0); + } + } + toconsole = false; + } else if (!strcmp (commands->command, cmd_chan_query)) { + if (v && line.length () > 4) { + QString ch = line.mid (4); + setTitle (ch); + KMPlayer::PlayListItem * lvi = static_cast <KMPlayer::PlayListItem *> (v->playList ()->findItem (ch, 0)); + if (lvi && lvi->node != m_last_channel) { + KMPlayer::PlayListItem * si = static_cast <KMPlayer::PlayListItem *> (v->playList ()->selectedItem ()); + bool jump_selection = (si && (si->node == m_document || si->node == m_last_channel)); + if (m_last_channel) + m_last_channel->setState (KMPlayer::Node::state_finished); + m_last_channel = lvi->node; + if (m_last_channel) + m_last_channel->setState (KMPlayer::Node::state_began); + if (jump_selection) { + v->playList ()->setSelected (lvi, true); + v->playList ()->ensureItemVisible (lvi); + } + v->playList ()->triggerUpdate (); + } + //v->playList ()->selectItem (ch); + int c = strtol(ch.ascii(), 0L, 10); + if (c != last_channel) { + last_channel = c; + m_app->statusBar ()->changeItem (QString::number (c), + id_status_timer); + } + } + } else if (cmd_done && !strcmp(commands->command,cmd_volume_query)){ + int pos = line.findRev (QChar (' ')); + if (pos > 0) { + QString vol = line.mid (pos + 1); + if (!vol.compare ("mute")) + m_stored_volume = 0; + else + m_stored_volume = vol.toInt (); + if (m_stored_volume == 0) + volumeChanged (m_app->view ()->controlPanel ()->volumeBar ()->value ()); + } + } + if (v && toconsole) + v->addText (QString (line), true); + line = readbuf.getReadLine (); + } + if (cmd_done) { + VDRCommand * c = commands->next; + delete commands; + commands = c; + if (commands) + sendCommand (); + else { + killTimer (timeout_timer); + timeout_timer = 0; + } + } + } + delete [] data; +} + +KDE_NO_EXPORT void KMPlayerVDRSource::socketError (int code) { + if (code == QSocket::ErrHostNotFound) { + KMessageBox::error (m_configpage, i18n ("Host not found"), i18n ("Error")); + } else if (code == QSocket::ErrConnectionRefused) { + KMessageBox::error (m_configpage, i18n ("Connection refused"), i18n ("Error")); + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::queueCommand (const char * cmd) { + if (m_player->source () != this) + return; + if (!commands) { + readbuf.clear (); + commands = new VDRCommand (cmd); + if (m_socket->state () == QSocket::Connected) { + sendCommand (); + } else { + m_socket->connectToHost ("127.0.0.1", tcp_port); + commands = new VDRCommand ("connect", commands); + } + } else { + VDRCommand * c = commands; + for (int i = 0; i < 10; ++i, c = c->next) + if (!c->next) { + c->next = new VDRCommand (cmd); + break; + } + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::queueCommand (const char * cmd, int t) { + queueCommand (cmd); + killTimer (channel_timer); + channel_timer = startTimer (t); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::sendCommand () { + //kdDebug () << "sendCommand " << commands->command << endl; + m_socket->writeBlock (commands->command, strlen(commands->command)); + m_socket->flush (); + killTimer (timeout_timer); + timeout_timer = startTimer (30000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::customCmd () { +#if KDE_IS_VERSION(3, 1, 90) + QString cmd = KInputDialog::getText (i18n ("Custom VDR command"), i18n ("You can pass commands to VDR.\nEnter 'HELP' to see a list of available commands.\nYou can see VDR response in the console window.\n\nVDR Command:"), QString(), 0, m_player->view ()); + if (!cmd.isEmpty ()) + queueCommand (QString (cmd + QChar ('\n')).local8Bit ()); +#endif +} + +KDE_NO_EXPORT void KMPlayerVDRSource::timerEvent (QTimerEvent * e) { + if (e->timerId () == timeout_timer || e->timerId () == finish_timer) { + deleteCommands (); + } else if (e->timerId () == channel_timer) { + queueCommand (cmd_chan_query); + killTimer (channel_timer); + channel_timer = startTimer (30000); + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::deleteCommands () { + killTimer (timeout_timer); + timeout_timer = 0; + killTimer (channel_timer); + channel_timer = 0; + for (VDRCommand * c = commands; c; c = commands) { + commands = commands->next; + delete c; + } + readbuf.clear (); + if (finish_timer) { + killTimer (finish_timer); + QApplication::eventLoop ()->exitLoop (); + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::jump (KMPlayer::NodePtr e) { + if (!e->isPlayable ()) return; + m_current = e; + jump (e->mrl ()->pretty_name); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::jump (const QString & channel) { + QCString c ("CHAN "); + QCString ch = channel.local8Bit (); + int p = ch.find (' '); + if (p > 0) + c += ch.left (p); + else + c += ch; // hope for the best .. + c += '\n'; + queueCommand (c); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::forward () { + queueCommand ("CHAN +\n", 1000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::backward () { + queueCommand ("CHAN -\n", 1000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyUp () { + queueCommand ("HITK UP\n", 1000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyDown () { + queueCommand ("HITK DOWN\n", 1000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyBack () { + queueCommand ("HITK BACK\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyOk () { + queueCommand ("HITK OK\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keySetup () { + queueCommand ("HITK SETUP\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyChannels () { + queueCommand ("HITK CHANNELS\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyMenu () { + queueCommand ("HITK MENU\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key0 () { + queueCommand ("HITK 0\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key1 () { + queueCommand ("HITK 1\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key2 () { + queueCommand ("HITK 2\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key3 () { + queueCommand ("HITK 3\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key4 () { + queueCommand ("HITK 4\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key5 () { + queueCommand ("HITK 5\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key6 () { + queueCommand ("HITK 6\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key7 () { + queueCommand ("HITK 7\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key8 () { + queueCommand ("HITK 8\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::key9 () { + queueCommand ("HITK 9\n", 2000); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyRed () { + queueCommand ("HITK RED\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyGreen () { + queueCommand ("HITK GREEN\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyYellow () { + queueCommand ("HITK YELLOW\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::keyBlue () { + queueCommand ("HITK BLUE\n"); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::write (KConfig * m_config) { + m_config->setGroup (strVDR); + m_config->writeEntry (strVDRPort, tcp_port); + m_config->writeEntry (strXVPort, m_xvport); + m_config->writeEntry (strXVEncoding, m_xvencoding); + m_config->writeEntry (strXVScale, scale); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::read (KConfig * m_config) { + m_config->setGroup (strVDR); + tcp_port = m_config->readNumEntry (strVDRPort, 2001); + m_xvport = m_config->readNumEntry (strXVPort, 0); + m_xvencoding = m_config->readNumEntry (strXVEncoding, 0); + scale = m_config->readNumEntry (strXVScale, 0); +} + +struct XVTreeItem : public QListViewItem { + XVTreeItem (QListViewItem *parent, const QString & t, int p, int e) + : QListViewItem (parent, t), port (p), encoding (e) {} + int port; + int encoding; +}; + +KDE_NO_EXPORT void KMPlayerVDRSource::sync (bool fromUI) { + XVideo * xvideo = static_cast<XVideo *>(m_player->players()["xvideo"]); + if (fromUI) { + tcp_port = m_configpage->tcp_port->text ().toInt (); + scale = m_configpage->scale->id (m_configpage->scale->selected ()); + setAspect (m_document, scale ? 16.0/9 : 1.25); + XVTreeItem * vitem = dynamic_cast <XVTreeItem *> (m_configpage->xv_port->selectedItem ()); + if (vitem) { + m_xvport = vitem->port; + m_xvencoding = vitem->encoding; + } + } else { + m_configpage->tcp_port->setText (QString::number (tcp_port)); + m_configpage->scale->setButton (scale); + QListViewItem * vitem = m_configpage->xv_port->firstChild (); + NodePtr configdoc = xvideo->configDocument (); + if (configdoc && configdoc->firstChild ()) { + for (QListViewItem *i=vitem->firstChild(); i; i=vitem->firstChild()) + delete i; + NodePtr node = configdoc->firstChild (); + for (node = node->firstChild (); node; node = node->nextSibling()) { + if (!node->isElementNode ()) + continue; // some text sneaked in ? + Element * elm = convertNode <Element> (node); + if (elm->getAttribute (KMPlayer::StringPool::attr_type) != + QString ("tree")) + continue; + for (NodePtr n = elm->firstChild (); n; n = n->nextSibling ()) { + if (!n->isElementNode () || strcmp (n->nodeName (), "Port")) + continue; + Element * e = convertNode <Element> (n); + QString portatt = e->getAttribute ( + KMPlayer::StringPool::attr_value); + int port; + QListViewItem *pi = new QListViewItem (vitem, i18n ("Port ") + portatt); + port = portatt.toInt (); + for (NodePtr in=e->firstChild(); in; in=in->nextSibling()) { + if (!in->isElementNode () || + strcmp (in->nodeName (), "Input")) + continue; + Element * i = convertNode <Element> (in); + QString inp = i->getAttribute ( + KMPlayer::StringPool::attr_name); + int enc = i->getAttribute ( + KMPlayer::StringPool::attr_value).toInt (); + QListViewItem * ii = new XVTreeItem(pi, inp, port, enc); + if (m_xvport == port && enc == m_xvencoding) { + ii->setSelected (true); + m_configpage->xv_port->ensureItemVisible (ii); + } + } + } + } + } else // wait for showEvent + connect (xvideo, SIGNAL (configReceived()), this, SLOT (configReceived())); + } +} + +KDE_NO_EXPORT void KMPlayerVDRSource::configReceived () { + XVideo * xvideo = static_cast<XVideo *>(m_player->players()["xvideo"]); + disconnect (xvideo, SIGNAL (configReceived()), this, SLOT (configReceived())); + sync (false); +} + +KDE_NO_EXPORT void KMPlayerVDRSource::prefLocation (QString & item, QString & icon, QString & tab) { + item = i18n ("Source"); + icon = QString ("source"); + tab = i18n ("VDR"); +} + +KDE_NO_EXPORT QFrame * KMPlayerVDRSource::prefPage (QWidget * parent) { + if (!m_configpage) + m_configpage = new KMPlayerPrefSourcePageVDR (parent, m_player); + return m_configpage; +} + +KDE_NO_EXPORT bool KMPlayerVDRSource::requestPlayURL (KMPlayer::NodePtr) { + return true; +} + +KDE_NO_EXPORT void KMPlayerVDRSource::stateElementChanged (KMPlayer::Node *, KMPlayer::Node::State, KMPlayer::Node::State) { +} + +//----------------------------------------------------------------------------- + +static const char * xv_supported [] = { + "tvsource", "vdrsource", 0L +}; + +KDE_NO_CDTOR_EXPORT XVideo::XVideo (QObject * parent, Settings * settings) + : KMPlayer::CallbackProcess (parent, settings, "xvideo", i18n ("X&Video")) { + m_supported_sources = xv_supported; + //m_player->settings ()->addPage (m_configpage); +} + +KDE_NO_CDTOR_EXPORT XVideo::~XVideo () {} + +KDE_NO_EXPORT bool XVideo::ready (KMPlayer::Viewer * v) { + if (playing ()) { + return true; + } + initProcess (v); + QString cmd = QString ("kxvplayer -wid %3 -cb %4").arg (viewer ()->embeddedWinId ()).arg (dcopName ()); + if (m_have_config == config_unknown || m_have_config == config_probe) + cmd += QString (" -c"); + if (m_source) { + int xv_port = m_source->xvPort (); + int xv_encoding = m_source->xvEncoding (); + int freq = m_source->frequency (); + cmd += QString (" -port %1 -enc %2 -norm \"%3\"").arg (xv_port).arg (xv_encoding).arg (m_source->videoNorm ()); + if (freq > 0) + cmd += QString (" -freq %1").arg (freq); + } + fprintf (stderr, "%s\n", cmd.latin1 ()); + *m_process << cmd; + m_process->start (KProcess::NotifyOnExit, KProcess::All); + return m_process->isRunning (); +} + +#include "kmplayervdr.moc" diff --git a/src/kmplayervdr.h b/src/kmplayervdr.h new file mode 100644 index 0000000..4f11e8f --- /dev/null +++ b/src/kmplayervdr.h @@ -0,0 +1,169 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KMPLAYER_VDR_SOURCE_H +#define KMPLAYER_VDR_SOURCE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qframe.h> + +#include <kurl.h> + +#include "kmplayerappsource.h" +#include "kmplayerconfig.h" +#include "kmplayerprocess.h" + + +class KMPlayerApp; +class VDRCommand; +class KURLRequester; +class QButtonGroup; +class QMenuItem; +class QCheckBox; +class QLineEdit; +class KAction; +class QSocket; +class QTimerEvent; +class KListView; + +/* + * Preference page for VDR + */ +class KMPLAYER_NO_EXPORT KMPlayerPrefSourcePageVDR : public QFrame { + Q_OBJECT +public: + KMPlayerPrefSourcePageVDR (QWidget * parent, KMPlayer::PartBase * player); + ~KMPlayerPrefSourcePageVDR (); + KURLRequester * vcddevice; + KListView * xv_port; + QLineEdit * tcp_port; + QButtonGroup * scale; +protected: + void showEvent (QShowEvent *); +private: + KMPlayer::PartBase * m_player; +}; + + +/* + * Source from VDR (XVideo actually) and socket connection + */ +class KMPLAYER_NO_EXPORT KMPlayerVDRSource : public KMPlayer::Source, public KMPlayer::PreferencesPage { + Q_OBJECT +public: + KMPlayerVDRSource (KMPlayerApp * app); + virtual ~KMPlayerVDRSource (); + virtual bool hasLength (); + virtual bool isSeekable (); + virtual QString prettyName (); + virtual void write (KConfig *); + virtual void read (KConfig *); + virtual void sync (bool); + virtual void prefLocation (QString & item, QString & icon, QString & tab); + virtual QFrame * prefPage (QWidget * parent); + virtual bool requestPlayURL (KMPlayer::NodePtr mrl); + virtual void stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State os, KMPlayer::Node::State ns); + void waitForConnectionClose (); +public slots: + void activate (); + void deactivate (); + void jump (KMPlayer::NodePtr e); + void forward (); + void backward (); + void playCurrent (); + void toggleConnected (); + void volumeChanged (int); +private slots: + void keyUp (); + void keyDown (); + void keyBack (); + void keyOk (); + void keySetup (); + void keyChannels (); + void keyMenu (); + void key0 (); + void key1 (); + void key2 (); + void key3 (); + void key4 (); + void key5 (); + void key6 (); + void key7 (); + void key8 (); + void key9 (); + void keyRed (); + void keyGreen (); + void keyYellow (); + void keyBlue (); + void customCmd (); + void connected (); + void disconnected (); + void readyRead (); + void socketError (int); + void processStopped (); + void processStarted (); + void configReceived (); +protected: + void timerEvent (QTimerEvent *); +private: + enum { + act_up = 0, act_down, act_back, act_ok, + act_setup, act_channels, act_menu, + act_red, act_green, act_yellow, act_blue, + act_0, act_1, act_2, act_3, act_4, act_5, act_6, act_7, act_8, act_9, +#if KDE_IS_VERSION(3, 1, 90) + act_custom, +#endif + act_last + }; + void queueCommand (const char * cmd); + void queueCommand (const char * cmd, int repeat_ms); + void sendCommand (); + void deleteCommands (); + void jump (const QString & channel); + KMPlayerApp * m_app; + KMPlayerPrefSourcePageVDR * m_configpage; + KAction * m_actions [act_last]; + KAction * m_fullscreen_actions [act_last]; + QSocket * m_socket; + VDRCommand * commands; + QString m_request_jump; + KMPlayer::NodePtrW m_last_channel; + int channel_timer; + int timeout_timer; + int finish_timer; + int tcp_port; + int m_stored_volume; + int scale; + int last_channel; +}; + +class XVideo : public KMPlayer::CallbackProcess { + Q_OBJECT +public: + XVideo (QObject * parent, KMPlayer::Settings * settings); + ~XVideo (); +public slots: + virtual bool ready (KMPlayer::Viewer *); +}; + +#endif // KMPLAYER_VDR_SOURCE_H diff --git a/src/kmplayerview.cpp b/src/kmplayerview.cpp new file mode 100644 index 0000000..d55be16 --- /dev/null +++ b/src/kmplayerview.cpp @@ -0,0 +1,831 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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 <stdio.h> +#include <math.h> + +#include <config.h> +// include files for Qt +#include <qstyle.h> +#include <qtimer.h> +#include <qpainter.h> +#include <qmetaobject.h> +#include <qlayout.h> +#include <qpixmap.h> +#include <qtextedit.h> +#include <qtooltip.h> +#include <qapplication.h> +#include <qiconset.h> +#include <qcursor.h> +#include <qkeysequence.h> +#include <qslider.h> +#include <qlabel.h> +#include <qdatastream.h> +#include <qwidgetstack.h> +#include <qcursor.h> +#include <qclipboard.h> + +#include <kiconloader.h> +#include <kstatusbar.h> +#include <kdebug.h> +#include <klocale.h> +#include <kapplication.h> +#include <kactioncollection.h> +#include <kstdaction.h> +#include <kshortcut.h> +#include <kurldrag.h> +#include <kfinddialog.h> +#include <dcopclient.h> +#include <kglobalsettings.h> +#include <kstaticdeleter.h> + +#include "kmplayerview.h" +#include "kmplayercontrolpanel.h" +#include "kmplayersource.h" +#include "playlistview.h" +#include "viewarea.h" + +#include <X11/Xlib.h> +#include <X11/keysym.h> +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +static const int XKeyPress = KeyPress; +#undef KeyPress +#undef Always +#undef Never +#undef Status +#undef Unsorted +#undef Bool + +extern const char * normal_window_xpm[]; +extern const char * playlist_xpm[]; + + +/* mouse invisible: define the time (in 1/1000 seconds) before mouse goes invisible */ + + +using namespace KMPlayer; + +//------------------------------------------------------------------------- + +namespace KMPlayer { + +class KMPlayerPictureWidget : public QWidget { + View * m_view; +public: + KDE_NO_CDTOR_EXPORT KMPlayerPictureWidget (QWidget * parent, View * view) + : QWidget (parent), m_view (view) {} + KDE_NO_CDTOR_EXPORT ~KMPlayerPictureWidget () {} +protected: + void mousePressEvent (QMouseEvent *); +}; + +} // namespace + +KDE_NO_EXPORT void KMPlayerPictureWidget::mousePressEvent (QMouseEvent *) { + m_view->emitPictureClicked (); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT TextEdit::TextEdit (QWidget * parent, View * view) : QTextEdit (parent, "kde_kmplayer_console"), m_view (view) { + setReadOnly (true); + setPaper (QBrush (QColor (0, 0, 0))); + setColor (QColor (0xB2, 0xB2, 0xB2)); +} + +KDE_NO_EXPORT void TextEdit::contextMenuEvent (QContextMenuEvent * e) { + m_view->controlPanel ()->popupMenu ()->exec (e->globalPos ()); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT InfoWindow::InfoWindow (QWidget * parent, View * view) : QTextEdit (parent, "kde_kmplayer_console"), 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, const char *name) + : KMediaPlayer::View (parent, name), + m_image (0L), + m_control_panel (0L), + m_status_bar (0L), + m_volume_slider (0L), + m_mixer_object ("kicker"), + m_controlpanel_mode (CP_Show), + m_old_controlpanel_mode (CP_Show), + m_statusbar_mode (SB_Hide), + controlbar_timer (0), + infopanel_timer (0), + m_keepsizeratio (false), + m_playing (false), + m_mixer_init (false), + m_inVolumeUpdate (false), + m_tmplog_needs_eol (false), + m_revert_fullscreen (false), + m_no_info (false), + m_edit_mode (false) +{} + +KDE_NO_EXPORT void View::dropEvent (QDropEvent * de) { + KURL::List sl; + if (KURLDrag::canDecode (de)) { + KURLDrag::decode (de, sl); + } else if (QTextDrag::canDecode (de)) { + QString text; + QTextDrag::decode (de, text); + sl.push_back (KURL (text)); + } + if (sl.size () > 0) { + for (unsigned i = 0; i < sl.size (); i++) + sl [i] = KURL::decode_string (sl [i].url ()); + m_widgetstack->visibleWidget ()->setFocus (); + emit urlDropped (sl); + de->accept (); + } +} + +KDE_NO_EXPORT void View::dragEnterEvent (QDragEnterEvent* dee) { + if (isDragValid (dee)) + dee->accept (); +} + +KDE_NO_EXPORT void View::init (KActionCollection * action_collection) { + setBackgroundMode(Qt::NoBackground); // prevents flashing + //m_dockarea->setEraseColor (QColor (0, 0, 0)); + QPalette pal (QColor (64, 64,64), QColor (32, 32, 32)); + QVBoxLayout * viewbox = new QVBoxLayout (this, 0, 0); + m_dockarea = new KDockArea (this, "kde_kmplayer_dock_area"); + m_dock_video = new KDockWidget (m_dockarea->manager (), 0, KGlobal::iconLoader ()->loadIcon (QString ("kmplayer"), KIcon::Small), m_dockarea); + m_dock_video->setEraseColor (QColor (0, 0, 255)); + m_dock_video->setDockSite (KDockWidget::DockLeft | KDockWidget::DockBottom | KDockWidget::DockRight | KDockWidget::DockTop); + m_dock_video->setEnableDocking(KDockWidget::DockNone); + m_view_area = new ViewArea (m_dock_video, this); + m_dock_video->setWidget (m_view_area); + m_dockarea->setMainDockWidget (m_dock_video); + m_dock_playlist = m_dockarea->createDockWidget (i18n ("Play List"), KGlobal::iconLoader ()->loadIcon (QString ("player_playlist"), KIcon::Small)); + m_playlist = new PlayListView (m_dock_playlist, this, action_collection); + m_dock_playlist->setWidget (m_playlist); + viewbox->addWidget (m_dockarea); + m_widgetstack = new QWidgetStack (m_view_area); + m_control_panel = new ControlPanel (m_view_area, this); + m_control_panel->setMaximumSize (2500, controlPanel ()->maximumSize ().height ()); + m_status_bar = new StatusBar (m_view_area); + m_status_bar->insertItem (QString (""), 0); + QSize sbsize = m_status_bar->sizeHint (); + m_status_bar->hide (); + m_status_bar->setMaximumSize (2500, sbsize.height ()); + m_viewer = new Viewer (m_widgetstack, this); + m_widgettypes [WT_Video] = m_viewer; +#if KDE_IS_VERSION(3,1,90) + setVideoWidget (m_view_area); +#endif + + m_multiedit = new TextEdit (m_widgetstack, this); + m_multiedit->setTextFormat (Qt::PlainText); + QFont fnt = KGlobalSettings::fixedFont (); + m_multiedit->setFont (fnt); + m_widgettypes[WT_Console] = m_multiedit; + + m_widgettypes[WT_Picture] = new KMPlayerPictureWidget (m_widgetstack, this); + + m_dock_infopanel = m_dockarea->createDockWidget ("infopanel", KGlobal::iconLoader ()->loadIcon (QString ("info"), KIcon::Small)); + m_infopanel = new InfoWindow (m_dock_infopanel, this); + m_dock_infopanel->setWidget (m_infopanel); + + m_widgetstack->addWidget (m_viewer); + m_widgetstack->addWidget (m_multiedit); + m_widgetstack->addWidget (m_widgettypes[WT_Picture]); + + setFocusPolicy (QWidget::ClickFocus); + + setAcceptDrops (true); + m_view_area->resizeEvent (0L); + + kapp->installX11EventFilter (this); +} + +KDE_NO_CDTOR_EXPORT View::~View () { + delete m_image; + 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->getMainDockWidget () == m_dock_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 (!m_edit_mode && m_dock_infopanel->mayBeShow ()) + m_dock_infopanel->manualDock(m_dock_video,KDockWidget::DockBottom,80); + m_infopanel->setText (msg); + } +} + +void View::setStatusMessage (const QString & msg) { + if (m_statusbar_mode != SB_Hide) + m_status_bar->changeItem (msg, 0); +} + +void View::toggleShowPlaylist () { + if (m_controlpanel_mode == CP_Only) + return; + 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, m_playlist); + h += style.pixelMetric(QStyle::PM_DockWindowFrameWidth, m_playlist); + h +=style.pixelMetric(QStyle::PM_DockWindowHandleExtent,m_playlist); + for (QListViewItem *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 ? KDockWidget::DockTop : KDockWidget::DockLeft, perc); + } + } else + m_dock_playlist->undock (); +} + +void View::setViewOnly () { + if (m_dock_playlist->mayBeHide ()) + m_dock_playlist->undock (); + if (m_dock_infopanel->mayBeHide ()) + m_dock_infopanel->undock (); +} + +void View::setInfoPanelOnly () { + if (m_dock_playlist->mayBeHide ()) + m_dock_playlist->undock (); + m_dock_video->setEnableDocking (KDockWidget::DockCenter); + m_dock_video->undock (); + m_dock_infopanel->setEnableDocking (KDockWidget::DockNone); + m_dockarea->setMainDockWidget (m_dock_infopanel); +} + +void View::setPlaylistOnly () { + if (m_dock_infopanel->mayBeHide ()) + m_dock_infopanel->undock (); + m_dock_video->setEnableDocking (KDockWidget::DockCenter); + m_dock_video->undock (); + m_dock_playlist->setEnableDocking (KDockWidget::DockNone); + m_dockarea->setMainDockWidget (m_dock_playlist); +} + +void View::setEditMode (RootPlayListItem *ri, bool enable) { + m_edit_mode = enable; + m_infopanel->setReadOnly (!m_edit_mode); + m_infopanel->setTextFormat (enable ? Qt::PlainText : Qt::AutoText); + if (m_edit_mode && m_dock_infopanel->mayBeShow ()) + m_dock_infopanel->manualDock(m_dock_video,KDockWidget::DockBottom,50); + m_playlist->showAllNodes (ri, m_edit_mode); +} + +bool View::setPicture (const QString & path) { + delete m_image; + if (path.isEmpty ()) + m_image = 0L; + else { + m_image = new QPixmap (path); + if (m_image->isNull ()) { + delete m_image; + m_image = 0L; + kdDebug() << "View::setPicture failed " << path << endl; + } + } + if (!m_image) { + m_widgetstack->raiseWidget (m_viewer); + } else { + m_widgettypes[WT_Picture]->setPaletteBackgroundPixmap (*m_image); + m_widgetstack->raiseWidget (m_widgettypes[WT_Picture]); + setControlPanelMode (CP_AutoHide); + } + return m_image; +} + +KDE_NO_EXPORT void View::updateVolume () { + if (m_mixer_init && !m_volume_slider) + return; + QByteArray data, replydata; + QCString replyType; + int volume; + bool has_mixer = kapp->dcopClient ()->call (m_mixer_object, "Mixer0", + "masterVolume()", data, replyType, replydata); + if (!has_mixer) { + m_mixer_object = "kmix"; + has_mixer = kapp->dcopClient ()->call (m_mixer_object, "Mixer0", + "masterVolume()", data, replyType, replydata); + } + if (has_mixer) { + QDataStream replystream (replydata, IO_ReadOnly); + replystream >> volume; + if (!m_mixer_init) { + QLabel * mixer_label = new QLabel (i18n ("Volume:"), m_control_panel->popupMenu ()); + m_control_panel->popupMenu ()->insertItem (mixer_label, -1, 4); + m_volume_slider = new QSlider (0, 100, 10, volume, Qt::Horizontal, m_control_panel->popupMenu ()); + connect(m_volume_slider, SIGNAL(valueChanged(int)), this,SLOT(setVolume(int))); + m_control_panel->popupMenu ()->insertItem (m_volume_slider, ControlPanel::menu_volume, 5); + m_control_panel->popupMenu ()->insertSeparator (6); + } else { + m_inVolumeUpdate = true; + m_volume_slider->setValue (volume); + m_inVolumeUpdate = false; + } + } else if (m_volume_slider) { + m_control_panel->popupMenu ()->removeItemAt (6); + m_control_panel->popupMenu ()->removeItemAt (5); + m_control_panel->popupMenu ()->removeItemAt (4); + m_volume_slider = 0L; + } + m_mixer_init = true; +} + +void View::showWidget (WidgetType wt) { + m_widgetstack->raiseWidget (m_widgettypes [wt]); + if (m_widgetstack->visibleWidget () == m_widgettypes[WT_Console]) { + addText (QString (""), false); + if (m_controlpanel_mode == CP_AutoHide && m_playing) + m_control_panel->show(); + } else + delayedShowButtons (false); + updateLayout (); +} + +void View::toggleVideoConsoleWindow () { + WidgetType wt = WT_Console; + if (m_widgetstack->visibleWidget () == m_widgettypes[WT_Console]) { + wt = WT_Video; + m_control_panel->popupMenu ()->changeItem (ControlPanel::menu_video, KGlobal::iconLoader ()->loadIconSet (QString ("konsole"), KIcon::Small, 0, true), i18n ("Con&sole")); + } else + m_control_panel->popupMenu ()->changeItem (ControlPanel::menu_video, KGlobal::iconLoader ()->loadIconSet (QString ("video"), KIcon::Small, 0, true), i18n ("V&ideo")); + showWidget (wt); + emit windowVideoConsoleToggled (int (wt)); +} + +void View::setControlPanelMode (ControlPanelMode m) { + 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 (); + m_view_area->resizeEvent (0L); + } else if (m_controlpanel_mode == CP_AutoHide) { + if ((m_playing && + m_widgetstack->visibleWidget () != m_widgettypes[WT_Console])) + delayedShowButtons (false); + else if (!m_control_panel->isVisible ()) { + m_control_panel->show (); + m_view_area->resizeEvent (0L); + } + } else if (m_controlpanel_mode == CP_Hide && m_control_panel->isVisible()) { + m_control_panel->hide (); + m_view_area->resizeEvent (0L); + } +} + +void View::setStatusBarMode (StatusBarMode m) { + m_statusbar_mode = m; + if (m == SB_Hide) + m_status_bar->hide (); + else + m_status_bar->show (); + 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_widgetstack->visibleWidget () == m_widgettypes[WT_Picture]) && + m_widgetstack->visibleWidget () != m_widgettypes[WT_Console] && + !controlbar_timer) { + controlbar_timer = startTimer (500); + } +} + +KDE_NO_EXPORT void View::setVolume (int vol) { + if (m_inVolumeUpdate) return; + QByteArray data; + QDataStream arg( data, IO_WriteOnly ); + arg << vol; + if (!kapp->dcopClient()->send (m_mixer_object, "Mixer0", "setMasterVolume(int)", data)) + kdWarning() << "Failed to update volume" << endl; +} + +KDE_NO_EXPORT void View::updateLayout () { + if (m_controlpanel_mode == CP_Only) + m_control_panel->setMaximumSize (2500, 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_widgetstack->visibleWidget () == m_widgettypes[WT_Picture]) { + 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->text ().isEmpty ()) + m_dock_infopanel->undock (); + infopanel_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_widgetstack->visibleWidget () != m_widgettypes[WT_Console] && + tmplog.length () < 7500) + return; + if (eol) { + m_multiedit->append (tmplog); + tmplog.truncate (0); + m_tmplog_needs_eol = false; + } else { + int pos = tmplog.findRev (QChar ('\n')); + if (pos >= 0) { + m_multiedit->append (tmplog.left (pos)); + tmplog = tmplog.mid (pos+1); + } + } + int p = m_multiedit->paragraphs (); + if (5000 < p) { + m_multiedit->setSelection (0, 0, p - 4499, 0); + m_multiedit->removeSelectedText (); + } + m_multiedit->setCursorPosition (m_multiedit->paragraphs () - 1, 0); +} + +/* void View::print (QPrinter *pPrinter) +{ + QPainter printpainter; + printpainter.begin (pPrinter); + + // TODO: add your printing code here + + printpainter.end (); +}*/ + +KDE_NO_EXPORT void View::videoStart () { + if (m_dockarea->getMainDockWidget () != m_dock_video) { + // restore from an info or playlist only setting + KDockWidget * dw = m_dockarea->getMainDockWidget (); + dw->setEnableDocking (KDockWidget::DockCenter); + dw->undock (); + m_dock_video->setEnableDocking (KDockWidget::DockNone); + m_dockarea->setMainDockWidget (m_dock_video); + m_view_area->resizeEvent (0L); + } + if (m_controlpanel_mode == CP_Only) { + m_control_panel->setMaximumSize(2500, controlPanel()->preferedHeight()); + setControlPanelMode (CP_Show); + } +} + +KDE_NO_EXPORT void View::playingStart () { + if (m_playing) return; //FIXME: make symetric with playingStop + if (m_widgetstack->visibleWidget () == m_widgettypes[WT_Picture]) + m_widgetstack->raiseWidget (m_viewer); + 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_widgetstack->visibleWidget () != m_widgettypes[WT_Picture]) { + m_control_panel->show (); + //m_view_area->setMouseTracking (false); + } + killTimer (controlbar_timer); + controlbar_timer = 0; + m_playing = false; + WId w = m_viewer->embeddedWinId (); + if (w) + XClearWindow (qt_xdisplay(), w); + 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->popupMenu ()->activateItemAt (m_control_panel->popupMenu ()->indexOf (ControlPanel::menu_fullscreen)); + //m_view_area->fullScreen (); + playingStop (); + m_viewer->show (); +} + +bool View::isFullScreen () const { + return m_view_area->isFullScreen (); +} + +void View::fullScreen () { + if (!m_view_area->isFullScreen()) { + m_sreensaver_disabled = false; + 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_view_area->fullScreen(); + m_control_panel->popupMenu ()->setItemVisible (ControlPanel::menu_zoom, false); + m_widgetstack->visibleWidget ()->setFocus (); + } else { + if (m_sreensaver_disabled) + m_sreensaver_disabled = !kapp->dcopClient()->send + ("kdesktop", "KScreensaverIface", "enable(bool)", "true"); + m_view_area->fullScreen(); + m_control_panel->popupMenu ()->setItemVisible (ControlPanel::menu_zoom, true); + } + 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; +} + +bool View::x11Event (XEvent * e) { + switch (e->type) { + case UnmapNotify: + if (e->xunmap.event == m_viewer->embeddedWinId ()) { + videoStart (); + //hide(); + } + break; + case XKeyPress: + if (e->xkey.window == m_viewer->embeddedWinId ()) { + KeySym ksym; + char kbuf[16]; + XLookupString (&e->xkey, kbuf, sizeof(kbuf), &ksym, NULL); + switch (ksym) { + case XK_f: + case XK_F: + //fullScreen (); + break; + }; + } + break; + /*case ColormapNotify: + fprintf (stderr, "colormap notify\n"); + return true;*/ + case MotionNotify: + if (e->xmotion.window == m_viewer->embeddedWinId ()) + delayedShowButtons (e->xmotion.y > m_view_area->height () - + statusBarHeight () - + m_control_panel->maximumSize ().height ()); + m_view_area->mouseMoved (); + break; + case MapNotify: + if (e->xmap.event == m_viewer->embeddedWinId ()) { + show (); + QTimer::singleShot (10, m_viewer, SLOT (sendConfigureEvent ())); + } + break; + /*case ConfigureNotify: + break; + //return true;*/ + default: + break; + } + return false; +} + +//---------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT Viewer::Viewer (QWidget *parent, View * view) + : QXEmbed (parent), m_plain_window (0), m_bgcolor (0), m_aspect (0.0), + m_view (view) { + /*XWindowAttributes xwa; + XGetWindowAttributes (qt_xdisplay(), winId (), &xwa); + XSetWindowAttributes xswa; + xswa.background_pixel = 0; + xswa.border_pixel = 0; + xswa.colormap = xwa.colormap; + create (XCreateWindow (qt_xdisplay (), parent->winId (), 0, 0, 10, 10, 0, + x11Depth (), InputOutput, (Visual*)x11Visual (), + CWBackPixel | CWBorderPixel | CWColormap, &xswa));*/ + setAcceptDrops (true); + initialize (); + //setProtocol (QXEmbed::XPLAIN); +} + +KDE_NO_CDTOR_EXPORT Viewer::~Viewer () { +} + +KDE_NO_EXPORT void Viewer::changeProtocol (QXEmbed::Protocol p) { + kdDebug () << "changeProtocol " << (int)protocol () << "->" << p << endl; + if (!embeddedWinId () || p != protocol ()) { + if (p == QXEmbed::XPLAIN) { + setProtocol (p); + if (!m_plain_window) { + int scr = DefaultScreen (qt_xdisplay ()); + m_plain_window = XCreateSimpleWindow ( + qt_xdisplay(), + m_view->winId (), + 0, 0, width(), height(), + 1, + BlackPixel (qt_xdisplay(), scr), + BlackPixel (qt_xdisplay(), scr)); + embed (m_plain_window); + } + XClearWindow (qt_xdisplay(), m_plain_window); + } else { + if (m_plain_window) { + XDestroyWindow (qt_xdisplay(), m_plain_window); + m_plain_window = 0; + XSync (qt_xdisplay (), false); + } + //setProtocol (p); + setProtocol (QXEmbed::XPLAIN); + } + } +} + +KDE_NO_EXPORT void Viewer::windowChanged (WId w) { + kdDebug () << "windowChanged " << (int)w << endl; + if (w /*&& m_plain_window*/) + XSelectInput (qt_xdisplay (), w, + //KeyPressMask | KeyReleaseMask | + KeyPressMask | + //EnterWindowMask | LeaveWindowMask | + //FocusChangeMask | + ExposureMask | + StructureNotifyMask | + PointerMotionMask); +} + +KDE_NO_EXPORT void Viewer::mouseMoveEvent (QMouseEvent * e) { + if (e->state () == Qt::NoButton) { + int cp_height = m_view->controlPanel ()->maximumSize ().height (); + m_view->delayedShowButtons (e->y () > height () - cp_height); + } + m_view->viewArea ()->mouseMoved (); +} + +void Viewer::setAspect (float a) { + m_aspect = a; +} + +KDE_NO_EXPORT int Viewer::heightForWidth (int w) const { + if (m_aspect <= 0.01) + return 0; + return int (w/m_aspect); +} + +KDE_NO_EXPORT void Viewer::dropEvent (QDropEvent * de) { + m_view->dropEvent (de); +} + +KDE_NO_EXPORT void Viewer::dragEnterEvent (QDragEnterEvent* dee) { + m_view->dragEnterEvent (dee); +} +/* +*/ +void Viewer::sendKeyEvent (int key) { + WId w = embeddedWinId (); + if (w) { + char buf[2] = { char (key), '\0' }; + KeySym keysym = XStringToKeysym (buf); + XKeyEvent event = { + XKeyPress, 0, true, + qt_xdisplay (), w, qt_xrootwin(), w, + /*time*/ 0, 0, 0, 0, 0, + 0, XKeysymToKeycode (qt_xdisplay (), keysym), true + }; + XSendEvent (qt_xdisplay(), w, false, KeyPressMask, (XEvent *) &event); + XFlush (qt_xdisplay ()); + } +} + +KDE_NO_EXPORT void Viewer::sendConfigureEvent () { + WId w = embeddedWinId (); + if (w) { + XConfigureEvent c = { + ConfigureNotify, 0UL, True, + qt_xdisplay (), w, winId (), + x (), y (), width (), height (), + 0, None, False + }; + XSendEvent(qt_xdisplay(),c.event,true,StructureNotifyMask,(XEvent*)&c); + XFlush (qt_xdisplay ()); + } +} + +KDE_NO_EXPORT void Viewer::contextMenuEvent (QContextMenuEvent * e) { + m_view->controlPanel ()->popupMenu ()->exec (e->globalPos ()); +} + +KDE_NO_EXPORT void Viewer::setBackgroundColor (const QColor & c) { + if (m_bgcolor != c.rgb ()) { + m_bgcolor = c.rgb (); + setCurrentBackgroundColor (c); + } +} + +KDE_NO_EXPORT void Viewer::resetBackgroundColor () { + setCurrentBackgroundColor (m_bgcolor); +} + +KDE_NO_EXPORT void Viewer::setCurrentBackgroundColor (const QColor & c) { + setPaletteBackgroundColor (c); + WId w = embeddedWinId (); + if (w) { + XSetWindowBackground (qt_xdisplay (), w, c.rgb ()); + XFlush (qt_xdisplay ()); + } +} + +#include "kmplayerview.moc" diff --git a/src/kmplayerview.h b/src/kmplayerview.h new file mode 100644 index 0000000..d255bd0 --- /dev/null +++ b/src/kmplayerview.h @@ -0,0 +1,243 @@ +/** + * Copyright (C) 2002-2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef KMPLAYERVIEW_H +#define KMPLAYERVIEW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <qwidget.h> +#include <qtextedit.h> + +#include <kdockwidget.h> +#include <kurl.h> +#include <qxembed.h> +#include <kmediaplayer/view.h> + +#include "kmplayersource.h" + +#define MOUSE_INVISIBLE_DELAY 2000 + +class QWidgetStack; +class QPixmap; +class QPaintDevice; +class QPainter; +class QSlider; +class QLabel; +class KActionCollection; +class KAction; +class KShortcut; +class KStatusBar; +class KFindDialog; + +namespace KMPlayer { + +class View; +class ViewArea; +class Viewer; +class ControlPanel; +class VolumeBar; +class Console; +class PlayListView; +class PlayListView; +class RootPlayListItem; + +typedef KStatusBar StatusBar; + +/* + * The console GUI + */ +class TextEdit : public QTextEdit { +public: + TextEdit (QWidget * parent, View * view); +protected: + void contextMenuEvent (QContextMenuEvent * e); +private: + View * m_view; +}; + +/* + * The infowindow GUI + */ +class InfoWindow : public QTextEdit { +public: + InfoWindow (QWidget * parent, View * view); + KDE_NO_EXPORT View * view () const { return m_view; } +protected: + void contextMenuEvent (QContextMenuEvent * e); +private: + View * m_view; +}; + +/* + * The view containing ViewArea and playlist + */ +class KMPLAYER_EXPORT View : public KMediaPlayer::View { + Q_OBJECT +public: + enum ControlPanelMode { + CP_Hide, CP_AutoHide, CP_Show, CP_Only /* no video widget */ + }; + enum StatusBarMode { + SB_Hide, SB_Show, SB_Only /* no video widget */ + }; + enum WidgetType { + WT_Video, WT_Console, WT_Picture, WT_Last + }; + + View (QWidget *parent, const char *); + ~View(); + + void addText (const QString &, bool eol=false); + void init (KActionCollection * ac); + void reset (); + //void print(QPrinter *pPrinter); + + TextEdit * console () const { return m_multiedit; } + KDE_NO_EXPORT Viewer * viewer () const { return m_viewer; } + KDE_NO_EXPORT ControlPanel * controlPanel () const {return m_control_panel;} + KDE_NO_EXPORT StatusBar * statusBar () const {return m_status_bar;} + KDE_NO_EXPORT PlayListView * playList () const { return m_playlist; } + KDE_NO_EXPORT InfoWindow * infoPanel () const { return m_infopanel; } + KDE_NO_EXPORT QWidgetStack * widgetStack () const { return m_widgetstack; } + KDE_NO_EXPORT KDockArea * docArea () const { return m_dockarea; } + KDE_NO_EXPORT ViewArea * viewArea () const { return m_view_area; } + KDE_NO_EXPORT bool keepSizeRatio () const { return m_keepsizeratio; } + void setKeepSizeRatio (bool b); + void showWidget (WidgetType w); + void setControlPanelMode (ControlPanelMode m); + void setStatusBarMode (StatusBarMode m); + void setEraseColor (const QColor &); + KDE_NO_EXPORT ControlPanelMode controlPanelMode () const { return m_controlpanel_mode; } + KDE_NO_EXPORT StatusBarMode statusBarMode () const { return m_statusbar_mode; } + void delayedShowButtons (bool show); + bool isFullScreen () const; + int statusBarHeight () const; + KDE_NO_EXPORT bool editMode () const { return m_edit_mode; } + bool setPicture (const QString & path); + KDE_NO_EXPORT QPixmap * image () const { return m_image; } + void setNoInfoMessages (bool b) { m_no_info = b; } + void setViewOnly (); + void setInfoPanelOnly (); + void setPlaylistOnly (); + void setEditMode (RootPlayListItem *, bool enable=true); + void dragEnterEvent (QDragEnterEvent *); + void dropEvent (QDropEvent *); + KDE_NO_EXPORT void emitPictureClicked () { emit pictureClicked (); } + /* raise video widget, might (auto) hides panel */ + void videoStart (); + void playingStart (); + /* shows panel */ + void playingStop (); +public slots: + void setVolume (int); + void updateVolume (); + void fullScreen (); + void updateLayout (); + void toggleShowPlaylist (); + void toggleVideoConsoleWindow (); + void setInfoMessage (const QString & msg); + void setStatusMessage (const QString & msg); +signals: + void urlDropped (const KURL::List & urls); + void pictureClicked (); + void fullScreenChanged (); + void windowVideoConsoleToggled (int wt); +protected: + void leaveEvent (QEvent *) KDE_NO_EXPORT; + void timerEvent (QTimerEvent *) KDE_NO_EXPORT; + bool x11Event (XEvent *) KDE_NO_EXPORT; +private: + // widget for player's output + Viewer * m_viewer; + // console output + TextEdit * m_multiedit; + // widget stack contains m_viewer, m_multiedit and m_picturewidget + QWidgetStack * m_widgetstack; + // widget that layouts m_widgetstack for ratio setting and m_control_panel + ViewArea * m_view_area; + // playlist widget + PlayListView * m_playlist; + // infopanel widget + InfoWindow * m_infopanel; + // all widget types + QWidget * m_widgettypes [WT_Last]; + KDockArea * m_dockarea; + KDockWidget * m_dock_video; + KDockWidget * m_dock_playlist; + KDockWidget * m_dock_infopanel; + QString tmplog; + QPixmap * m_image; + ControlPanel * m_control_panel; + StatusBar * m_status_bar; + QSlider * m_volume_slider; + const char * m_mixer_object; + ControlPanelMode m_controlpanel_mode; + ControlPanelMode m_old_controlpanel_mode; + StatusBarMode m_statusbar_mode; + int controlbar_timer; + int infopanel_timer; + bool m_keepsizeratio; + bool m_playing; + bool m_mixer_init; + bool m_inVolumeUpdate; + bool m_sreensaver_disabled; + bool m_tmplog_needs_eol; + bool m_revert_fullscreen; + bool m_no_info; + bool m_edit_mode; +}; + +/* + * The video widget + */ +class KMPLAYER_EXPORT Viewer : public QXEmbed { + Q_OBJECT +public: + Viewer(QWidget *parent, View * view); + ~Viewer(); + + int heightForWidth (int w) const; + + void setAspect (float a); + float aspect () { return m_aspect; } + void sendKeyEvent (int key); + void setBackgroundColor (const QColor & c); + void resetBackgroundColor (); + void setCurrentBackgroundColor (const QColor & c); + KDE_NO_EXPORT View * view () const { return m_view; } + void changeProtocol (QXEmbed::Protocol p); +public slots: + void sendConfigureEvent (); +protected: + void dragEnterEvent (QDragEnterEvent *); + void dropEvent (QDropEvent *); + void mouseMoveEvent (QMouseEvent * e); + void contextMenuEvent (QContextMenuEvent * e); + virtual void windowChanged( WId w ); +private: + WId m_plain_window; + unsigned int m_bgcolor; + float m_aspect; + View * m_view; +}; + +} // namespace + +#endif // KMPLAYERVIEW_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c10df5b --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + main.cpp - description + ------------------- +begin : Sat Dec 7 16:14:51 CET 2002 +copyright : (C) 2002 by Koos Vriezen +email : + ***************************************************************************/ + +/*************************************************************************** +* * +* 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. * +* * + ***************************************************************************/ +#include <unistd.h> + +#include <config.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kdemacros.h> +#include <dcopclient.h> + +#include <qguardedptr.h> +#include <qfileinfo.h> + +#include "kmplayer.h" + +static const char description[] = I18N_NOOP("KMPlayer"); + + +static KCmdLineOptions options[] = +{ + { "+[File]", I18N_NOOP("file to open"), 0 }, + KCmdLineLastOption + // INSERT YOUR COMMANDLINE OPTIONS HERE +}; + +extern "C" { + + KDE_EXPORT int kdemain (int argc, char *argv[]) + { + setsid (); + + KAboutData aboutData ("kmplayer", I18N_NOOP ("KMPlayer"), + VERSION, description, KAboutData::License_GPL, + "(c) 2002-2005, Koos Vriezen", 0, 0, ""); + aboutData.addAuthor( "Koos Vriezen",0, ""); + KCmdLineArgs::init (argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions (options); // Add our own options. + + KMPlayer::StringPool::init(); + + KApplication app; + QGuardedPtr <KMPlayerApp> kmplayer; + + if (app.isRestored ()) { + RESTORE (KMPlayerApp); + } else { + kmplayer = new KMPlayerApp (); + kmplayer->show(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KURL url; + if (args->count () == 1) + url = args->url (0); + if (args->count () > 1) + for (int i = 0; i < args->count (); i++) { + KURL url = args->url (i); + if (url.url ().find ("://") < 0) + url = KURL (QFileInfo (url.url ()).absFilePath ()); + if (url.isValid ()) + kmplayer->addURL (url); + } + kmplayer->openDocumentFile (url); + args->clear (); + } + app.dcopClient()->registerAs("kmplayer"); + int retvalue = app.exec (); + + delete kmplayer; + + KMPlayer::StringPool::reset(); + + return retvalue; + } +} diff --git a/src/moz-sdk/jni.h b/src/moz-sdk/jni.h new file mode 100644 index 0000000..863075a --- /dev/null +++ b/src/moz-sdk/jni.h @@ -0,0 +1,1810 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Java Runtime Interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation and Sun Microsystems, Inc. + * Portions created by the Initial Developer are Copyright (C) 1993-1996 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef JNI_H +#define JNI_H + +#include <stdio.h> +#include <stdarg.h> + +/* jni_md.h contains the machine-dependent typedefs for jbyte, jint + and jlong */ + +#include "jni_md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * JNI Types + */ + +typedef unsigned char jboolean; +typedef unsigned short jchar; +typedef short jshort; +typedef float jfloat; +typedef double jdouble; + +typedef jint jsize; + +#ifdef __cplusplus + +class _jobject {}; +class _jclass : public _jobject {}; +class _jthrowable : public _jobject {}; +class _jstring : public _jobject {}; +class _jarray : public _jobject {}; +class _jbooleanArray : public _jarray {}; +class _jbyteArray : public _jarray {}; +class _jcharArray : public _jarray {}; +class _jshortArray : public _jarray {}; +class _jintArray : public _jarray {}; +class _jlongArray : public _jarray {}; +class _jfloatArray : public _jarray {}; +class _jdoubleArray : public _jarray {}; +class _jobjectArray : public _jarray {}; + +typedef _jobject *jobject; +typedef _jclass *jclass; +typedef _jthrowable *jthrowable; +typedef _jstring *jstring; +typedef _jarray *jarray; +typedef _jbooleanArray *jbooleanArray; +typedef _jbyteArray *jbyteArray; +typedef _jcharArray *jcharArray; +typedef _jshortArray *jshortArray; +typedef _jintArray *jintArray; +typedef _jlongArray *jlongArray; +typedef _jfloatArray *jfloatArray; +typedef _jdoubleArray *jdoubleArray; +typedef _jobjectArray *jobjectArray; + +#else + +struct _jobject; + +typedef struct _jobject *jobject; +typedef jobject jclass; +typedef jobject jthrowable; +typedef jobject jstring; +typedef jobject jarray; +typedef jarray jbooleanArray; +typedef jarray jbyteArray; +typedef jarray jcharArray; +typedef jarray jshortArray; +typedef jarray jintArray; +typedef jarray jlongArray; +typedef jarray jfloatArray; +typedef jarray jdoubleArray; +typedef jarray jobjectArray; + +#endif + +#if 0 /* moved to jri_md.h */ +typedef jobject jref; /* For transition---not meant to be part of public + API anymore.*/ +#endif + +typedef union jvalue { + jboolean z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong j; + jfloat f; + jdouble d; + jobject l; +} jvalue; + +struct _jfieldID; +typedef struct _jfieldID *jfieldID; + +struct _jmethodID; +typedef struct _jmethodID *jmethodID; + +/* + * jboolean constants + */ + +#define JNI_FALSE 0 +#define JNI_TRUE 1 + +/* + * possible return values for JNI functions. + */ + +#define JNI_OK 0 +#define JNI_ERR (-1) + +/* + * used in ReleaseScalarArrayElements + */ + +#define JNI_COMMIT 1 +#define JNI_ABORT 2 + +/* + * used in RegisterNatives to describe native method name, signature, + * and function pointer. + */ + +typedef struct { + char *name; + char *signature; + void *fnPtr; +} JNINativeMethod; + +/* + * JNI Native Method Interface. + */ + +struct JNINativeInterface_; + +struct JNIEnv_; + +#ifdef __cplusplus +typedef JNIEnv_ JNIEnv; +#else +typedef const struct JNINativeInterface_ *JNIEnv; +#endif + +/* + * JNI Invocation Interface. + */ + +struct JNIInvokeInterface_; + +struct JavaVM_; + +#ifdef __cplusplus +typedef JavaVM_ JavaVM; +#else +typedef const struct JNIInvokeInterface_ *JavaVM; +#endif + +struct JNINativeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + void *reserved3; + jint (JNICALL *GetVersion)(JNIEnv *env); + + jclass (JNICALL *DefineClass) + (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, + jsize len); + jclass (JNICALL *FindClass) + (JNIEnv *env, const char *name); + + void *reserved4; + void *reserved5; + void *reserved6; + + jclass (JNICALL *GetSuperclass) + (JNIEnv *env, jclass sub); + jboolean (JNICALL *IsAssignableFrom) + (JNIEnv *env, jclass sub, jclass sup); + void *reserved7; + + + jint (JNICALL *Throw) + (JNIEnv *env, jthrowable obj); + jint (JNICALL *ThrowNew) + (JNIEnv *env, jclass clazz, const char *msg); + jthrowable (JNICALL *ExceptionOccurred) + (JNIEnv *env); + void (JNICALL *ExceptionDescribe) + (JNIEnv *env); + void (JNICALL *ExceptionClear) + (JNIEnv *env); + void (JNICALL *FatalError) + (JNIEnv *env, const char *msg); + void *reserved8; + void *reserved9; + + jobject (JNICALL *NewGlobalRef) + (JNIEnv *env, jobject lobj); + void (JNICALL *DeleteGlobalRef) + (JNIEnv *env, jobject gref); + void (JNICALL *DeleteLocalRef) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsSameObject) + (JNIEnv *env, jobject obj1, jobject obj2); + void *reserved10; + void *reserved11; + + jobject (JNICALL *AllocObject) + (JNIEnv *env, jclass clazz); + jobject (JNICALL *NewObject) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *NewObjectV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *NewObjectA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jclass (JNICALL *GetObjectClass) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsInstanceOf) + (JNIEnv *env, jobject obj, jclass clazz); + + jmethodID (JNICALL *GetMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallObjectMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jobject (JNICALL *CallObjectMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jobject (JNICALL *CallObjectMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args); + + jboolean (JNICALL *CallBooleanMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jboolean (JNICALL *CallBooleanMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jboolean (JNICALL *CallBooleanMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args); + + jbyte (JNICALL *CallByteMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jbyte (JNICALL *CallByteMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jbyte (JNICALL *CallByteMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + jchar (JNICALL *CallCharMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jchar (JNICALL *CallCharMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jchar (JNICALL *CallCharMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + jshort (JNICALL *CallShortMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jshort (JNICALL *CallShortMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jshort (JNICALL *CallShortMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + jint (JNICALL *CallIntMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jint (JNICALL *CallIntMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jint (JNICALL *CallIntMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + jlong (JNICALL *CallLongMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jlong (JNICALL *CallLongMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jlong (JNICALL *CallLongMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + jfloat (JNICALL *CallFloatMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jfloat (JNICALL *CallFloatMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jfloat (JNICALL *CallFloatMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + jdouble (JNICALL *CallDoubleMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jdouble (JNICALL *CallDoubleMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jdouble (JNICALL *CallDoubleMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args); + + void (JNICALL *CallVoidMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + void (JNICALL *CallVoidMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + void (JNICALL *CallVoidMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args); + + jobject (JNICALL *CallNonvirtualObjectMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallNonvirtualObjectMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jobject (JNICALL *CallNonvirtualObjectMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue * args); + + jboolean (JNICALL *CallNonvirtualBooleanMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallNonvirtualBooleanMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jboolean (JNICALL *CallNonvirtualBooleanMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue * args); + + jbyte (JNICALL *CallNonvirtualByteMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallNonvirtualByteMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jbyte (JNICALL *CallNonvirtualByteMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + jchar (JNICALL *CallNonvirtualCharMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallNonvirtualCharMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jchar (JNICALL *CallNonvirtualCharMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + jshort (JNICALL *CallNonvirtualShortMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallNonvirtualShortMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jshort (JNICALL *CallNonvirtualShortMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + jint (JNICALL *CallNonvirtualIntMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallNonvirtualIntMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jint (JNICALL *CallNonvirtualIntMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + jlong (JNICALL *CallNonvirtualLongMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallNonvirtualLongMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jlong (JNICALL *CallNonvirtualLongMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + jfloat (JNICALL *CallNonvirtualFloatMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallNonvirtualFloatMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jfloat (JNICALL *CallNonvirtualFloatMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + jdouble (JNICALL *CallNonvirtualDoubleMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallNonvirtualDoubleMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jdouble (JNICALL *CallNonvirtualDoubleMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue *args); + + void (JNICALL *CallNonvirtualVoidMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + void (JNICALL *CallNonvirtualVoidMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + void (JNICALL *CallNonvirtualVoidMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + jvalue * args); + + jfieldID (JNICALL *GetFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *GetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jboolean (JNICALL *GetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jbyte (JNICALL *GetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jchar (JNICALL *GetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jshort (JNICALL *GetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jint (JNICALL *GetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jlong (JNICALL *GetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jfloat (JNICALL *GetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jdouble (JNICALL *GetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + + void (JNICALL *SetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); + void (JNICALL *SetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); + void (JNICALL *SetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); + void (JNICALL *SetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); + void (JNICALL *SetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); + void (JNICALL *SetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); + void (JNICALL *SetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); + void (JNICALL *SetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); + void (JNICALL *SetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); + + jmethodID (JNICALL *GetStaticMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallStaticObjectMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallStaticObjectMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *CallStaticObjectMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jboolean (JNICALL *CallStaticBooleanMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallStaticBooleanMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jboolean (JNICALL *CallStaticBooleanMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jbyte (JNICALL *CallStaticByteMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallStaticByteMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jbyte (JNICALL *CallStaticByteMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jchar (JNICALL *CallStaticCharMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallStaticCharMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jchar (JNICALL *CallStaticCharMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jshort (JNICALL *CallStaticShortMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallStaticShortMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jshort (JNICALL *CallStaticShortMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jint (JNICALL *CallStaticIntMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallStaticIntMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jint (JNICALL *CallStaticIntMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jlong (JNICALL *CallStaticLongMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallStaticLongMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jlong (JNICALL *CallStaticLongMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jfloat (JNICALL *CallStaticFloatMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallStaticFloatMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jfloat (JNICALL *CallStaticFloatMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + jdouble (JNICALL *CallStaticDoubleMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallStaticDoubleMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jdouble (JNICALL *CallStaticDoubleMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args); + + void (JNICALL *CallStaticVoidMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, ...); + void (JNICALL *CallStaticVoidMethodV) + (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); + void (JNICALL *CallStaticVoidMethodA) + (JNIEnv *env, jclass cls, jmethodID methodID, jvalue * args); + + jfieldID (JNICALL *GetStaticFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + jobject (JNICALL *GetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jboolean (JNICALL *GetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jbyte (JNICALL *GetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jchar (JNICALL *GetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jshort (JNICALL *GetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jint (JNICALL *GetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jlong (JNICALL *GetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jfloat (JNICALL *GetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jdouble (JNICALL *GetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + + void (JNICALL *SetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); + void (JNICALL *SetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); + void (JNICALL *SetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); + void (JNICALL *SetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); + void (JNICALL *SetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); + void (JNICALL *SetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); + void (JNICALL *SetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); + void (JNICALL *SetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); + void (JNICALL *SetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); + + jstring (JNICALL *NewString) + (JNIEnv *env, const jchar *unicode, jsize len); + jsize (JNICALL *GetStringLength) + (JNIEnv *env, jstring str); + const jchar *(JNICALL *GetStringChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringChars) + (JNIEnv *env, jstring str, const jchar *chars); + + jstring (JNICALL *NewStringUTF) + (JNIEnv *env, const char *utf); + jsize (JNICALL *GetStringUTFLength) + (JNIEnv *env, jstring str); + const char* (JNICALL *GetStringUTFChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringUTFChars) + (JNIEnv *env, jstring str, const char* chars); + + + jsize (JNICALL *GetArrayLength) + (JNIEnv *env, jarray array); + + jobjectArray (JNICALL *NewObjectArray) + (JNIEnv *env, jsize len, jclass clazz, jobject init); + jobject (JNICALL *GetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index); + void (JNICALL *SetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index, jobject val); + + jbooleanArray (JNICALL *NewBooleanArray) + (JNIEnv *env, jsize len); + jbyteArray (JNICALL *NewByteArray) + (JNIEnv *env, jsize len); + jcharArray (JNICALL *NewCharArray) + (JNIEnv *env, jsize len); + jshortArray (JNICALL *NewShortArray) + (JNIEnv *env, jsize len); + jintArray (JNICALL *NewIntArray) + (JNIEnv *env, jsize len); + jlongArray (JNICALL *NewLongArray) + (JNIEnv *env, jsize len); + jfloatArray (JNICALL *NewFloatArray) + (JNIEnv *env, jsize len); + jdoubleArray (JNICALL *NewDoubleArray) + (JNIEnv *env, jsize len); + + jboolean * (JNICALL *GetBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *isCopy); + jbyte * (JNICALL *GetByteArrayElements) + (JNIEnv *env, jbyteArray array, jboolean *isCopy); + jchar * (JNICALL *GetCharArrayElements) + (JNIEnv *env, jcharArray array, jboolean *isCopy); + jshort * (JNICALL *GetShortArrayElements) + (JNIEnv *env, jshortArray array, jboolean *isCopy); + jint * (JNICALL *GetIntArrayElements) + (JNIEnv *env, jintArray array, jboolean *isCopy); + jlong * (JNICALL *GetLongArrayElements) + (JNIEnv *env, jlongArray array, jboolean *isCopy); + jfloat * (JNICALL *GetFloatArrayElements) + (JNIEnv *env, jfloatArray array, jboolean *isCopy); + jdouble * (JNICALL *GetDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jboolean *isCopy); + + void (JNICALL *ReleaseBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); + void (JNICALL *ReleaseByteArrayElements) + (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); + void (JNICALL *ReleaseCharArrayElements) + (JNIEnv *env, jcharArray array, jchar *elems, jint mode); + void (JNICALL *ReleaseShortArrayElements) + (JNIEnv *env, jshortArray array, jshort *elems, jint mode); + void (JNICALL *ReleaseIntArrayElements) + (JNIEnv *env, jintArray array, jint *elems, jint mode); + void (JNICALL *ReleaseLongArrayElements) + (JNIEnv *env, jlongArray array, jlong *elems, jint mode); + void (JNICALL *ReleaseFloatArrayElements) + (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); + void (JNICALL *ReleaseDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); + + void (JNICALL *GetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); + void (JNICALL *GetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); + void (JNICALL *GetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); + void (JNICALL *GetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); + void (JNICALL *GetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); + void (JNICALL *GetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); + void (JNICALL *GetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); + void (JNICALL *GetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); + + void (JNICALL *SetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); + void (JNICALL *SetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); + void (JNICALL *SetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); + void (JNICALL *SetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); + void (JNICALL *SetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); + void (JNICALL *SetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); + void (JNICALL *SetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); + void (JNICALL *SetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); + + jint (JNICALL *RegisterNatives) + (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, + jint nMethods); + jint (JNICALL *UnregisterNatives) + (JNIEnv *env, jclass clazz); + + jint (JNICALL *MonitorEnter) + (JNIEnv *env, jobject obj); + jint (JNICALL *MonitorExit) + (JNIEnv *env, jobject obj); + + jint (JNICALL *GetJavaVM) + (JNIEnv *env, JavaVM **vm); +}; + +/* + * We use inlined functions for C++ so that programmers can write: + * + * env->FindClass("java/lang/String") + * + * in C++ rather than: + * + * (*env)->FindClass(env, "java/lang/String") + * + * in C. + */ + +struct JNIEnv_ { + const struct JNINativeInterface_ *functions; + void *reserved0; + void *reserved1[6]; +#ifdef __cplusplus + + jint GetVersion() { + return functions->GetVersion(this); + } + jclass DefineClass(const char *name, jobject loader, const jbyte *buf, + jsize len) { + return functions->DefineClass(this, name, loader, buf, len); + } + jclass FindClass(const char *name) { + return functions->FindClass(this, name); + } + jclass GetSuperclass(jclass sub) { + return functions->GetSuperclass(this, sub); + } + jboolean IsAssignableFrom(jclass sub, jclass sup) { + return functions->IsAssignableFrom(this, sub, sup); + } + + jint Throw(jthrowable obj) { + return functions->Throw(this, obj); + } + jint ThrowNew(jclass clazz, const char *msg) { + return functions->ThrowNew(this, clazz, msg); + } + jthrowable ExceptionOccurred() { + return functions->ExceptionOccurred(this); + } + void ExceptionDescribe() { + functions->ExceptionDescribe(this); + } + void ExceptionClear() { + functions->ExceptionClear(this); + } + void FatalError(const char *msg) { + functions->FatalError(this, msg); + } + + jobject NewGlobalRef(jobject lobj) { + return functions->NewGlobalRef(this,lobj); + } + void DeleteGlobalRef(jobject gref) { + functions->DeleteGlobalRef(this,gref); + } + void DeleteLocalRef(jobject obj) { + functions->DeleteLocalRef(this, obj); + } + + jboolean IsSameObject(jobject obj1, jobject obj2) { + return functions->IsSameObject(this,obj1,obj2); + } + + jobject AllocObject(jclass clazz) { + return functions->AllocObject(this,clazz); + } + jobject NewObject(jclass clazz, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args, methodID); + result = functions->NewObjectV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject NewObjectV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->NewObjectV(this,clazz,methodID,args); + } + jobject NewObjectA(jclass clazz, jmethodID methodID, + jvalue *args) { + return functions->NewObjectA(this,clazz,methodID,args); + } + + jclass GetObjectClass(jobject obj) { + return functions->GetObjectClass(this,obj); + } + jboolean IsInstanceOf(jobject obj, jclass clazz) { + return functions->IsInstanceOf(this,obj,clazz); + } + + jmethodID GetMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetMethodID(this,clazz,name,sig); + } + + jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallObjectMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jobject CallObjectMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallObjectMethodV(this,obj,methodID,args); + } + jobject CallObjectMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallObjectMethodA(this,obj,methodID,args); + } + + jboolean CallBooleanMethod(jobject obj, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallBooleanMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallBooleanMethodV(this,obj,methodID,args); + } + jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallBooleanMethodA(this,obj,methodID, args); + } + + jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallByteMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jbyte CallByteMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallByteMethodV(this,obj,methodID,args); + } + jbyte CallByteMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallByteMethodA(this,obj,methodID,args); + } + + jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallCharMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jchar CallCharMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallCharMethodV(this,obj,methodID,args); + } + jchar CallCharMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallCharMethodA(this,obj,methodID,args); + } + + jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallShortMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jshort CallShortMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallShortMethodV(this,obj,methodID,args); + } + jshort CallShortMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallShortMethodA(this,obj,methodID,args); + } + + jint CallIntMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallIntMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jint CallIntMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallIntMethodV(this,obj,methodID,args); + } + jint CallIntMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallIntMethodA(this,obj,methodID,args); + } + + jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallLongMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jlong CallLongMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallLongMethodV(this,obj,methodID,args); + } + jlong CallLongMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallLongMethodA(this,obj,methodID,args); + } + + jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallFloatMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jfloat CallFloatMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallFloatMethodV(this,obj,methodID,args); + } + jfloat CallFloatMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallFloatMethodA(this,obj,methodID,args); + } + + jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallDoubleMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallDoubleMethodV(this,obj,methodID,args); + } + jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + return functions->CallDoubleMethodA(this,obj,methodID,args); + } + + void CallVoidMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallVoidMethodV(this,obj,methodID,args); + va_end(args); + } + void CallVoidMethodV(jobject obj, jmethodID methodID, + va_list args) { + functions->CallVoidMethodV(this,obj,methodID,args); + } + void CallVoidMethodA(jobject obj, jmethodID methodID, + jvalue * args) { + functions->CallVoidMethodA(this,obj,methodID,args); + } + + jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + } + jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualObjectMethodA(this,obj,clazz, + methodID,args); + } + + jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + } + jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, + methodID, args); + } + + jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + } + jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualByteMethodA(this,obj,clazz, + methodID,args); + } + + jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + } + jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualCharMethodA(this,obj,clazz, + methodID,args); + } + + jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + } + jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualShortMethodA(this,obj,clazz, + methodID,args); + } + + jint CallNonvirtualIntMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + } + jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualIntMethodA(this,obj,clazz, + methodID,args); + } + + jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + } + jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, + jmethodID methodID, jvalue * args) { + return functions->CallNonvirtualLongMethodA(this,obj,clazz, + methodID,args); + } + + jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + } + jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, + jmethodID methodID, + jvalue * args) { + return functions->CallNonvirtualFloatMethodA(this,obj,clazz, + methodID,args); + } + + jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + } + jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, + jmethodID methodID, + jvalue * args) { + return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, + methodID,args); + } + + void CallNonvirtualVoidMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + va_end(args); + } + void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + } + void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, + jmethodID methodID, + jvalue * args) { + functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); + } + + jfieldID GetFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetFieldID(this,clazz,name,sig); + } + + jobject GetObjectField(jobject obj, jfieldID fieldID) { + return functions->GetObjectField(this,obj,fieldID); + } + jboolean GetBooleanField(jobject obj, jfieldID fieldID) { + return functions->GetBooleanField(this,obj,fieldID); + } + jbyte GetByteField(jobject obj, jfieldID fieldID) { + return functions->GetByteField(this,obj,fieldID); + } + jchar GetCharField(jobject obj, jfieldID fieldID) { + return functions->GetCharField(this,obj,fieldID); + } + jshort GetShortField(jobject obj, jfieldID fieldID) { + return functions->GetShortField(this,obj,fieldID); + } + jint GetIntField(jobject obj, jfieldID fieldID) { + return functions->GetIntField(this,obj,fieldID); + } + jlong GetLongField(jobject obj, jfieldID fieldID) { + return functions->GetLongField(this,obj,fieldID); + } + jfloat GetFloatField(jobject obj, jfieldID fieldID) { + return functions->GetFloatField(this,obj,fieldID); + } + jdouble GetDoubleField(jobject obj, jfieldID fieldID) { + return functions->GetDoubleField(this,obj,fieldID); + } + + void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { + functions->SetObjectField(this,obj,fieldID,val); + } + void SetBooleanField(jobject obj, jfieldID fieldID, + jboolean val) { + functions->SetBooleanField(this,obj,fieldID,val); + } + void SetByteField(jobject obj, jfieldID fieldID, + jbyte val) { + functions->SetByteField(this,obj,fieldID,val); + } + void SetCharField(jobject obj, jfieldID fieldID, + jchar val) { + functions->SetCharField(this,obj,fieldID,val); + } + void SetShortField(jobject obj, jfieldID fieldID, + jshort val) { + functions->SetShortField(this,obj,fieldID,val); + } + void SetIntField(jobject obj, jfieldID fieldID, + jint val) { + functions->SetIntField(this,obj,fieldID,val); + } + void SetLongField(jobject obj, jfieldID fieldID, + jlong val) { + functions->SetLongField(this,obj,fieldID,val); + } + void SetFloatField(jobject obj, jfieldID fieldID, + jfloat val) { + functions->SetFloatField(this,obj,fieldID,val); + } + void SetDoubleField(jobject obj, jfieldID fieldID, + jdouble val) { + functions->SetDoubleField(this,obj,fieldID,val); + } + + jmethodID GetStaticMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticMethodID(this,clazz,name,sig); + } + + jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, + ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->CallStaticObjectMethodV(this,clazz,methodID,args); + } + jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, + jvalue *args) { + return functions->CallStaticObjectMethodA(this,clazz,methodID,args); + } + + jboolean CallStaticBooleanMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jboolean CallStaticBooleanMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + } + jboolean CallStaticBooleanMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); + } + + jbyte CallStaticByteMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallStaticByteMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jbyte CallStaticByteMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticByteMethodV(this,clazz,methodID,args); + } + jbyte CallStaticByteMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticByteMethodA(this,clazz,methodID,args); + } + + jchar CallStaticCharMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallStaticCharMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jchar CallStaticCharMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticCharMethodV(this,clazz,methodID,args); + } + jchar CallStaticCharMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticCharMethodA(this,clazz,methodID,args); + } + + jshort CallStaticShortMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallStaticShortMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jshort CallStaticShortMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticShortMethodV(this,clazz,methodID,args); + } + jshort CallStaticShortMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticShortMethodA(this,clazz,methodID,args); + } + + jint CallStaticIntMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallStaticIntMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jint CallStaticIntMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticIntMethodV(this,clazz,methodID,args); + } + jint CallStaticIntMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticIntMethodA(this,clazz,methodID,args); + } + + jlong CallStaticLongMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallStaticLongMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jlong CallStaticLongMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticLongMethodV(this,clazz,methodID,args); + } + jlong CallStaticLongMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticLongMethodA(this,clazz,methodID,args); + } + + jfloat CallStaticFloatMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jfloat CallStaticFloatMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticFloatMethodV(this,clazz,methodID,args); + } + jfloat CallStaticFloatMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticFloatMethodA(this,clazz,methodID,args); + } + + jdouble CallStaticDoubleMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jdouble CallStaticDoubleMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + } + jdouble CallStaticDoubleMethodA(jclass clazz, + jmethodID methodID, jvalue *args) { + return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); + } + + void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallStaticVoidMethodV(this,cls,methodID,args); + va_end(args); + } + void CallStaticVoidMethodV(jclass cls, jmethodID methodID, + va_list args) { + functions->CallStaticVoidMethodV(this,cls,methodID,args); + } + void CallStaticVoidMethodA(jclass cls, jmethodID methodID, + jvalue * args) { + functions->CallStaticVoidMethodA(this,cls,methodID,args); + } + + jfieldID GetStaticFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticFieldID(this,clazz,name,sig); + } + jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticObjectField(this,clazz,fieldID); + } + jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticBooleanField(this,clazz,fieldID); + } + jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticByteField(this,clazz,fieldID); + } + jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticCharField(this,clazz,fieldID); + } + jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticShortField(this,clazz,fieldID); + } + jint GetStaticIntField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticIntField(this,clazz,fieldID); + } + jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticLongField(this,clazz,fieldID); + } + jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticFloatField(this,clazz,fieldID); + } + jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticDoubleField(this,clazz,fieldID); + } + + void SetStaticObjectField(jclass clazz, jfieldID fieldID, + jobject value) { + functions->SetStaticObjectField(this,clazz,fieldID,value); + } + void SetStaticBooleanField(jclass clazz, jfieldID fieldID, + jboolean value) { + functions->SetStaticBooleanField(this,clazz,fieldID,value); + } + void SetStaticByteField(jclass clazz, jfieldID fieldID, + jbyte value) { + functions->SetStaticByteField(this,clazz,fieldID,value); + } + void SetStaticCharField(jclass clazz, jfieldID fieldID, + jchar value) { + functions->SetStaticCharField(this,clazz,fieldID,value); + } + void SetStaticShortField(jclass clazz, jfieldID fieldID, + jshort value) { + functions->SetStaticShortField(this,clazz,fieldID,value); + } + void SetStaticIntField(jclass clazz, jfieldID fieldID, + jint value) { + functions->SetStaticIntField(this,clazz,fieldID,value); + } + void SetStaticLongField(jclass clazz, jfieldID fieldID, + jlong value) { + functions->SetStaticLongField(this,clazz,fieldID,value); + } + void SetStaticFloatField(jclass clazz, jfieldID fieldID, + jfloat value) { + functions->SetStaticFloatField(this,clazz,fieldID,value); + } + void SetStaticDoubleField(jclass clazz, jfieldID fieldID, + jdouble value) { + functions->SetStaticDoubleField(this,clazz,fieldID,value); + } + + jstring NewString(const jchar *unicode, jsize len) { + return functions->NewString(this,unicode,len); + } + jsize GetStringLength(jstring str) { + return functions->GetStringLength(this,str); + } + const jchar *GetStringChars(jstring str, jboolean *isCopy) { + return functions->GetStringChars(this,str,isCopy); + } + void ReleaseStringChars(jstring str, const jchar *chars) { + functions->ReleaseStringChars(this,str,chars); + } + + jstring NewStringUTF(const char *utf) { + return functions->NewStringUTF(this,utf); + } + jsize GetStringUTFLength(jstring str) { + return functions->GetStringUTFLength(this,str); + } + const char* GetStringUTFChars(jstring str, jboolean *isCopy) { + return functions->GetStringUTFChars(this,str,isCopy); + } + void ReleaseStringUTFChars(jstring str, const char* chars) { + functions->ReleaseStringUTFChars(this,str,chars); + } + + jsize GetArrayLength(jarray array) { + return functions->GetArrayLength(this,array); + } + + jobjectArray NewObjectArray(jsize len, jclass clazz, + jobject init) { + return functions->NewObjectArray(this,len,clazz,init); + } + jobject GetObjectArrayElement(jobjectArray array, jsize index) { + return functions->GetObjectArrayElement(this,array,index); + } + void SetObjectArrayElement(jobjectArray array, jsize index, + jobject val) { + functions->SetObjectArrayElement(this,array,index,val); + } + + jbooleanArray NewBooleanArray(jsize len) { + return functions->NewBooleanArray(this,len); + } + jbyteArray NewByteArray(jsize len) { + return functions->NewByteArray(this,len); + } + jcharArray NewCharArray(jsize len) { + return functions->NewCharArray(this,len); + } + jshortArray NewShortArray(jsize len) { + return functions->NewShortArray(this,len); + } + jintArray NewIntArray(jsize len) { + return functions->NewIntArray(this,len); + } + jlongArray NewLongArray(jsize len) { + return functions->NewLongArray(this,len); + } + jfloatArray NewFloatArray(jsize len) { + return functions->NewFloatArray(this,len); + } + jdoubleArray NewDoubleArray(jsize len) { + return functions->NewDoubleArray(this,len); + } + + jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { + return functions->GetBooleanArrayElements(this,array,isCopy); + } + jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { + return functions->GetByteArrayElements(this,array,isCopy); + } + jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { + return functions->GetCharArrayElements(this,array,isCopy); + } + jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { + return functions->GetShortArrayElements(this,array,isCopy); + } + jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { + return functions->GetIntArrayElements(this,array,isCopy); + } + jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { + return functions->GetLongArrayElements(this,array,isCopy); + } + jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { + return functions->GetFloatArrayElements(this,array,isCopy); + } + jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { + return functions->GetDoubleArrayElements(this,array,isCopy); + } + + void ReleaseBooleanArrayElements(jbooleanArray array, + jboolean *elems, + jint mode) { + functions->ReleaseBooleanArrayElements(this,array,elems,mode); + } + void ReleaseByteArrayElements(jbyteArray array, + jbyte *elems, + jint mode) { + functions->ReleaseByteArrayElements(this,array,elems,mode); + } + void ReleaseCharArrayElements(jcharArray array, + jchar *elems, + jint mode) { + functions->ReleaseCharArrayElements(this,array,elems,mode); + } + void ReleaseShortArrayElements(jshortArray array, + jshort *elems, + jint mode) { + functions->ReleaseShortArrayElements(this,array,elems,mode); + } + void ReleaseIntArrayElements(jintArray array, + jint *elems, + jint mode) { + functions->ReleaseIntArrayElements(this,array,elems,mode); + } + void ReleaseLongArrayElements(jlongArray array, + jlong *elems, + jint mode) { + functions->ReleaseLongArrayElements(this,array,elems,mode); + } + void ReleaseFloatArrayElements(jfloatArray array, + jfloat *elems, + jint mode) { + functions->ReleaseFloatArrayElements(this,array,elems,mode); + } + void ReleaseDoubleArrayElements(jdoubleArray array, + jdouble *elems, + jint mode) { + functions->ReleaseDoubleArrayElements(this,array,elems,mode); + } + + void GetBooleanArrayRegion(jbooleanArray array, + jsize start, jsize len, jboolean *buf) { + functions->GetBooleanArrayRegion(this,array,start,len,buf); + } + void GetByteArrayRegion(jbyteArray array, + jsize start, jsize len, jbyte *buf) { + functions->GetByteArrayRegion(this,array,start,len,buf); + } + void GetCharArrayRegion(jcharArray array, + jsize start, jsize len, jchar *buf) { + functions->GetCharArrayRegion(this,array,start,len,buf); + } + void GetShortArrayRegion(jshortArray array, + jsize start, jsize len, jshort *buf) { + functions->GetShortArrayRegion(this,array,start,len,buf); + } + void GetIntArrayRegion(jintArray array, + jsize start, jsize len, jint *buf) { + functions->GetIntArrayRegion(this,array,start,len,buf); + } + void GetLongArrayRegion(jlongArray array, + jsize start, jsize len, jlong *buf) { + functions->GetLongArrayRegion(this,array,start,len,buf); + } + void GetFloatArrayRegion(jfloatArray array, + jsize start, jsize len, jfloat *buf) { + functions->GetFloatArrayRegion(this,array,start,len,buf); + } + void GetDoubleArrayRegion(jdoubleArray array, + jsize start, jsize len, jdouble *buf) { + functions->GetDoubleArrayRegion(this,array,start,len,buf); + } + + void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, + jboolean *buf) { + functions->SetBooleanArrayRegion(this,array,start,len,buf); + } + void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, + jbyte *buf) { + functions->SetByteArrayRegion(this,array,start,len,buf); + } + void SetCharArrayRegion(jcharArray array, jsize start, jsize len, + jchar *buf) { + functions->SetCharArrayRegion(this,array,start,len,buf); + } + void SetShortArrayRegion(jshortArray array, jsize start, jsize len, + jshort *buf) { + functions->SetShortArrayRegion(this,array,start,len,buf); + } + void SetIntArrayRegion(jintArray array, jsize start, jsize len, + jint *buf) { + functions->SetIntArrayRegion(this,array,start,len,buf); + } + void SetLongArrayRegion(jlongArray array, jsize start, jsize len, + jlong *buf) { + functions->SetLongArrayRegion(this,array,start,len,buf); + } + void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, + jfloat *buf) { + functions->SetFloatArrayRegion(this,array,start,len,buf); + } + void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, + jdouble *buf) { + functions->SetDoubleArrayRegion(this,array,start,len,buf); + } + + jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, + jint nMethods) { + return functions->RegisterNatives(this,clazz,methods,nMethods); + } + jint UnregisterNatives(jclass clazz) { + return functions->UnregisterNatives(this,clazz); + } + + jint MonitorEnter(jobject obj) { + return functions->MonitorEnter(this,obj); + } + jint MonitorExit(jobject obj) { + return functions->MonitorExit(this,obj); + } + + jint GetJavaVM(JavaVM **vm) { + return functions->GetJavaVM(this,vm); + } + +#endif /* __cplusplus */ +}; + +/* These structures will be VM-specific. */ + +typedef struct JDK1_1InitArgs { + jint version; + + char **properties; + jint checkSource; + jint nativeStackSize; + jint javaStackSize; + jint minHeapSize; + jint maxHeapSize; + jint verifyMode; + char *classpath; + + jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args); + void (JNICALL *exit)(jint code); + void (JNICALL *abort)(); + + jint enableClassGC; + jint enableVerboseGC; + jint disableAsyncGC; + jint verbose; + jboolean debugging; + jint debugPort; +} JDK1_1InitArgs; + +typedef struct JDK1_1AttachArgs { + void * __padding; /* C compilers don't allow empty structures. */ +} JDK1_1AttachArgs; + +/* End VM-specific. */ + +struct JNIInvokeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + jint (JNICALL *DestroyJavaVM)(JavaVM *vm); + + jint (JNICALL *AttachCurrentThread) + (JavaVM *vm, JNIEnv **penv, void *args); + + jint (JNICALL *DetachCurrentThread)(JavaVM *vm); +}; + +struct JavaVM_ { + const struct JNIInvokeInterface_ *functions; + void *reserved0; + void *reserved1; + void *reserved2; +#ifdef __cplusplus + + jint DestroyJavaVM() { + return functions->DestroyJavaVM(this); + } + jint AttachCurrentThread(JNIEnv **penv, void *args) { + return functions->AttachCurrentThread(this, penv, args); + } + jint DetachCurrentThread() { + return functions->DetachCurrentThread(this); + } + +#endif +}; + +JNI_PUBLIC_API(void) JNI_GetDefaultJavaVMInitArgs(void *); + +JNI_PUBLIC_API(jint) JNI_CreateJavaVM(JavaVM **, JNIEnv **, void *); + +JNI_PUBLIC_API(jint) JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); +JNI_PUBLIC_API(jref) JNI_MakeLocalRef(JNIEnv *pJNIEnv, void *pHObject); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* JNI_H */ + + diff --git a/src/moz-sdk/jni_md.h b/src/moz-sdk/jni_md.h new file mode 100644 index 0000000..3c8c63d --- /dev/null +++ b/src/moz-sdk/jni_md.h @@ -0,0 +1,199 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/27/2000 IBM Corp. Set JNICALL to Optlink for + * use in OS2 + */ + +/******************************************************************************* + * Netscape version of jni_md.h -- depends on jri_md.h + ******************************************************************************/ + +#ifndef JNI_MD_H +#define JNI_MD_H + +#include "prtypes.h" /* needed for _declspec */ + +/******************************************************************************* + * WHAT'S UP WITH THIS FILE? + * + * This is where we define the mystical JNI_PUBLIC_API macro that works on all + * platforms. If you're running with Visual C++, Symantec C, or Borland's + * development environment on the PC, you're all set. Or if you're on the Mac + * with Metrowerks, Symantec or MPW with SC you're ok too. For UNIX it shouldn't + * matter. + + * Changes by sailesh on 9/26 + + * There are two symbols used in the declaration of the JNI functions + * and native code that uses the JNI: + * JNICALL - specifies the calling convention + * JNIEXPORT - specifies export status of the function + * + * The syntax to specify calling conventions is different in Win16 and + * Win32 - the brains at Micro$oft at work here. JavaSoft in their + * infinite wisdom cares for no platform other than Win32, and so they + * just define these two symbols as: + + #define JNIEXPORT __declspec(dllexport) + #define JNICALL __stdcall + + * We deal with this, in the way JRI defines the JRI_PUBLIC_API, by + * defining a macro called JNI_PUBLIC_API. Any of our developers who + * wish to use code for Win16 and Win32, _must_ use JNI_PUBLIC_API to + * be able to export functions properly. + + * Since we must also maintain compatibility with JavaSoft, we + * continue to define the symbol JNIEXPORT. However, use of this + * internally is deprecated, since it will cause a mess on Win16. + + * We _do not_ need a new symbol called JNICALL. Instead we + * redefine JNICALL in the same way JRI_CALLBACK was defined. + + ******************************************************************************/ + +/* DLL Entry modifiers... */ +#if defined(XP_OS2) +# ifdef XP_OS2_VACPP +# define JNI_PUBLIC_API(ResultType) ResultType _System +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNICALL _Optlink +# define JNIEXPORT +# else +# define JNI_PUBLIC_API(ResultType) ResultType +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNICALL +# define JNIEXPORT +# endif +/* Win32 */ +#elif defined(XP_WIN) || defined(_WINDOWS) || defined(WIN32) || defined(_WIN32) +# include <windows.h> +# if defined(_MSC_VER) || defined(__GNUC__) +# if defined(WIN32) || defined(_WIN32) +# define JNI_PUBLIC_API(ResultType) _declspec(dllexport) ResultType __stdcall +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNI_NATIVE_STUB(ResultType) _declspec(dllexport) ResultType +# define JNICALL __stdcall +# else /* !_WIN32 */ +# if defined(_WINDLL) +# define JNI_PUBLIC_API(ResultType) ResultType __cdecl __export __loadds +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNI_NATIVE_STUB(ResultType) ResultType __cdecl __loadds +# define JNICALL __loadds +# else /* !WINDLL */ +# define JNI_PUBLIC_API(ResultType) ResultType __cdecl __export +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNI_NATIVE_STUB(ResultType) ResultType __cdecl __export +# define JNICALL __export +# endif /* !WINDLL */ +# endif /* !_WIN32 */ +# elif defined(__BORLANDC__) +# if defined(WIN32) || defined(_WIN32) +# define JNI_PUBLIC_API(ResultType) __export ResultType +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNI_NATIVE_STUB(ResultType) __export ResultType +# define JNICALL +# else /* !_WIN32 */ +# define JNI_PUBLIC_API(ResultType) ResultType _cdecl _export _loadds +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNI_NATIVE_STUB(ResultType) ResultType _cdecl _loadds +# define JNICALL _loadds +# endif +# else +# error Unsupported PC development environment. +# endif +# ifndef IS_LITTLE_ENDIAN +# define IS_LITTLE_ENDIAN +# endif + /* This is the stuff inherited from JavaSoft .. */ +# define JNIEXPORT __declspec(dllexport) + + +/* Mac */ +#elif macintosh || Macintosh || THINK_C +# if defined(__MWERKS__) /* Metrowerks */ +# if !__option(enumsalwaysint) +# error You need to define 'Enums Always Int' for your project. +# endif +# if defined(TARGET_CPU_68K) && !TARGET_RT_MAC_CFM +# if !__option(fourbyteints) +# error You need to define 'Struct Alignment: 68k' for your project. +# endif +# endif /* !GENERATINGCFM */ +# define JNI_PUBLIC_API(ResultType) __declspec(export) ResultType +# define JNI_PUBLIC_VAR(VarType) JNI_PUBLIC_API(VarType) +# define JNI_NATIVE_STUB(ResultType) JNI_PUBLIC_API(ResultType) +# elif defined(__SC__) /* Symantec */ +# error What are the Symantec defines? ([email protected]) +# elif macintosh && applec /* MPW */ +# error Please upgrade to the latest MPW compiler (SC). +# else +# error Unsupported Mac development environment. +# endif +# define JNICALL + /* This is the stuff inherited from JavaSoft .. */ +# define JNIEXPORT + +/* Unix or else */ +#else +# define JNI_PUBLIC_API(ResultType) ResultType +# define JNI_PUBLIC_VAR(VarType) VarType +# define JNI_NATIVE_STUB(ResultType) ResultType +# define JNICALL + /* This is the stuff inherited from JavaSoft .. */ +# define JNIEXPORT +#endif + +#ifndef FAR /* for non-Win16 */ +#define FAR +#endif + +/* Get the rest of the stuff from jri_md.h */ +#include "jri_md.h" + +#endif /* JNI_MD_H */ diff --git a/src/moz-sdk/jri.h b/src/moz-sdk/jri.h new file mode 100644 index 0000000..866fc69 --- /dev/null +++ b/src/moz-sdk/jri.h @@ -0,0 +1,689 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/******************************************************************************* + * Java Runtime Interface + ******************************************************************************/ + +#ifndef JRI_H +#define JRI_H + +#include "jritypes.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/******************************************************************************* + * JRIEnv + ******************************************************************************/ + +/* The type of the JRIEnv interface. */ +typedef struct JRIEnvInterface JRIEnvInterface; + +/* The type of a JRIEnv instance. */ +typedef const JRIEnvInterface* JRIEnv; + +/******************************************************************************* + * JRIEnv Operations + ******************************************************************************/ + +#define JRI_DefineClass(env, classLoader, buf, bufLen) \ + (((*(env))->DefineClass)(env, JRI_DefineClass_op, classLoader, buf, bufLen)) + +#define JRI_FindClass(env, name) \ + (((*(env))->FindClass)(env, JRI_FindClass_op, name)) + +#define JRI_Throw(env, obj) \ + (((*(env))->Throw)(env, JRI_Throw_op, obj)) + +#define JRI_ThrowNew(env, clazz, message) \ + (((*(env))->ThrowNew)(env, JRI_ThrowNew_op, clazz, message)) + +#define JRI_ExceptionOccurred(env) \ + (((*(env))->ExceptionOccurred)(env, JRI_ExceptionOccurred_op)) + +#define JRI_ExceptionDescribe(env) \ + (((*(env))->ExceptionDescribe)(env, JRI_ExceptionDescribe_op)) + +#define JRI_ExceptionClear(env) \ + (((*(env))->ExceptionClear)(env, JRI_ExceptionClear_op)) + +#define JRI_NewGlobalRef(env, ref) \ + (((*(env))->NewGlobalRef)(env, JRI_NewGlobalRef_op, ref)) + +#define JRI_DisposeGlobalRef(env, gref) \ + (((*(env))->DisposeGlobalRef)(env, JRI_DisposeGlobalRef_op, gref)) + +#define JRI_GetGlobalRef(env, gref) \ + (((*(env))->GetGlobalRef)(env, JRI_GetGlobalRef_op, gref)) + +#define JRI_SetGlobalRef(env, gref, ref) \ + (((*(env))->SetGlobalRef)(env, JRI_SetGlobalRef_op, gref, ref)) + +#define JRI_IsSameObject(env, a, b) \ + (((*(env))->IsSameObject)(env, JRI_IsSameObject_op, a, b)) + +#define JRI_NewObject(env) ((*(env))->NewObject) +#define JRI_NewObjectV(env, clazz, methodID, args) \ + (((*(env))->NewObjectV)(env, JRI_NewObject_op_va_list, clazz, methodID, args)) +#define JRI_NewObjectA(env, clazz, method, args) \ + (((*(env))->NewObjectA)(env, JRI_NewObject_op_array, clazz, methodID, args)) + +#define JRI_GetObjectClass(env, obj) \ + (((*(env))->GetObjectClass)(env, JRI_GetObjectClass_op, obj)) + +#define JRI_IsInstanceOf(env, obj, clazz) \ + (((*(env))->IsInstanceOf)(env, JRI_IsInstanceOf_op, obj, clazz)) + +#define JRI_GetMethodID(env, clazz, name, sig) \ + (((*(env))->GetMethodID)(env, JRI_GetMethodID_op, clazz, name, sig)) + +#define JRI_CallMethod(env) ((*(env))->CallMethod) +#define JRI_CallMethodV(env, obj, methodID, args) \ + (((*(env))->CallMethodV)(env, JRI_CallMethod_op_va_list, obj, methodID, args)) +#define JRI_CallMethodA(env, obj, methodID, args) \ + (((*(env))->CallMethodA)(env, JRI_CallMethod_op_array, obj, methodID, args)) + +#define JRI_CallMethodBoolean(env) ((*(env))->CallMethodBoolean) +#define JRI_CallMethodBooleanV(env, obj, methodID, args) \ + (((*(env))->CallMethodBooleanV)(env, JRI_CallMethodBoolean_op_va_list, obj, methodID, args)) +#define JRI_CallMethodBooleanA(env, obj, methodID, args) \ + (((*(env))->CallMethodBooleanA)(env, JRI_CallMethodBoolean_op_array, obj, methodID, args)) + +#define JRI_CallMethodByte(env) ((*(env))->CallMethodByte) +#define JRI_CallMethodByteV(env, obj, methodID, args) \ + (((*(env))->CallMethodByteV)(env, JRI_CallMethodByte_op_va_list, obj, methodID, args)) +#define JRI_CallMethodByteA(env, obj, methodID, args) \ + (((*(env))->CallMethodByteA)(env, JRI_CallMethodByte_op_array, obj, methodID, args)) + +#define JRI_CallMethodChar(env) ((*(env))->CallMethodChar) +#define JRI_CallMethodCharV(env, obj, methodID, args) \ + (((*(env))->CallMethodCharV)(env, JRI_CallMethodChar_op_va_list, obj, methodID, args)) +#define JRI_CallMethodCharA(env, obj, methodID, args) \ + (((*(env))->CallMethodCharA)(env, JRI_CallMethodChar_op_array, obj, methodID, args)) + +#define JRI_CallMethodShort(env) ((*(env))->CallMethodShort) +#define JRI_CallMethodShortV(env, obj, methodID, args) \ + (((*(env))->CallMethodShortV)(env, JRI_CallMethodShort_op_va_list, obj, methodID, args)) +#define JRI_CallMethodShortA(env, obj, methodID, args) \ + (((*(env))->CallMethodShortA)(env, JRI_CallMethodShort_op_array, obj, methodID, args)) + +#define JRI_CallMethodInt(env) ((*(env))->CallMethodInt) +#define JRI_CallMethodIntV(env, obj, methodID, args) \ + (((*(env))->CallMethodIntV)(env, JRI_CallMethodInt_op_va_list, obj, methodID, args)) +#define JRI_CallMethodIntA(env, obj, methodID, args) \ + (((*(env))->CallMethodIntA)(env, JRI_CallMethodInt_op_array, obj, methodID, args)) + +#define JRI_CallMethodLong(env) ((*(env))->CallMethodLong) +#define JRI_CallMethodLongV(env, obj, methodID, args) \ + (((*(env))->CallMethodLongV)(env, JRI_CallMethodLong_op_va_list, obj, methodID, args)) +#define JRI_CallMethodLongA(env, obj, methodID, args) \ + (((*(env))->CallMethodLongA)(env, JRI_CallMethodLong_op_array, obj, methodID, args)) + +#define JRI_CallMethodFloat(env) ((*(env))->CallMethodFloat) +#define JRI_CallMethodFloatV(env, obj, methodID, args) \ + (((*(env))->CallMethodFloatV)(env, JRI_CallMethodFloat_op_va_list, obj, methodID, args)) +#define JRI_CallMethodFloatA(env, obj, methodID, args) \ + (((*(env))->CallMethodFloatA)(env, JRI_CallMethodFloat_op_array, obj, methodID, args)) + +#define JRI_CallMethodDouble(env) ((*(env))->CallMethodDouble) +#define JRI_CallMethodDoubleV(env, obj, methodID, args) \ + (((*(env))->CallMethodDoubleV)(env, JRI_CallMethodDouble_op_va_list, obj, methodID, args)) +#define JRI_CallMethodDoubleA(env, obj, methodID, args) \ + (((*(env))->CallMethodDoubleA)(env, JRI_CallMethodDouble_op_array, obj, methodID, args)) + +#define JRI_GetFieldID(env, clazz, name, sig) \ + (((*(env))->GetFieldID)(env, JRI_GetFieldID_op, clazz, name, sig)) + +#define JRI_GetField(env, obj, fieldID) \ + (((*(env))->GetField)(env, JRI_GetField_op, obj, fieldID)) + +#define JRI_GetFieldBoolean(env, obj, fieldID) \ + (((*(env))->GetFieldBoolean)(env, JRI_GetFieldBoolean_op, obj, fieldID)) + +#define JRI_GetFieldByte(env, obj, fieldID) \ + (((*(env))->GetFieldByte)(env, JRI_GetFieldByte_op, obj, fieldID)) + +#define JRI_GetFieldChar(env, obj, fieldID) \ + (((*(env))->GetFieldChar)(env, JRI_GetFieldChar_op, obj, fieldID)) + +#define JRI_GetFieldShort(env, obj, fieldID) \ + (((*(env))->GetFieldShort)(env, JRI_GetFieldShort_op, obj, fieldID)) + +#define JRI_GetFieldInt(env, obj, fieldID) \ + (((*(env))->GetFieldInt)(env, JRI_GetFieldInt_op, obj, fieldID)) + +#define JRI_GetFieldLong(env, obj, fieldID) \ + (((*(env))->GetFieldLong)(env, JRI_GetFieldLong_op, obj, fieldID)) + +#define JRI_GetFieldFloat(env, obj, fieldID) \ + (((*(env))->GetFieldFloat)(env, JRI_GetFieldFloat_op, obj, fieldID)) + +#define JRI_GetFieldDouble(env, obj, fieldID) \ + (((*(env))->GetFieldDouble)(env, JRI_GetFieldDouble_op, obj, fieldID)) + +#define JRI_SetField(env, obj, fieldID, value) \ + (((*(env))->SetField)(env, JRI_SetField_op, obj, fieldID, value)) + +#define JRI_SetFieldBoolean(env, obj, fieldID, value) \ + (((*(env))->SetFieldBoolean)(env, JRI_SetFieldBoolean_op, obj, fieldID, value)) + +#define JRI_SetFieldByte(env, obj, fieldID, value) \ + (((*(env))->SetFieldByte)(env, JRI_SetFieldByte_op, obj, fieldID, value)) + +#define JRI_SetFieldChar(env, obj, fieldID, value) \ + (((*(env))->SetFieldChar)(env, JRI_SetFieldChar_op, obj, fieldID, value)) + +#define JRI_SetFieldShort(env, obj, fieldID, value) \ + (((*(env))->SetFieldShort)(env, JRI_SetFieldShort_op, obj, fieldID, value)) + +#define JRI_SetFieldInt(env, obj, fieldID, value) \ + (((*(env))->SetFieldInt)(env, JRI_SetFieldInt_op, obj, fieldID, value)) + +#define JRI_SetFieldLong(env, obj, fieldID, value) \ + (((*(env))->SetFieldLong)(env, JRI_SetFieldLong_op, obj, fieldID, value)) + +#define JRI_SetFieldFloat(env, obj, fieldID, value) \ + (((*(env))->SetFieldFloat)(env, JRI_SetFieldFloat_op, obj, fieldID, value)) + +#define JRI_SetFieldDouble(env, obj, fieldID, value) \ + (((*(env))->SetFieldDouble)(env, JRI_SetFieldDouble_op, obj, fieldID, value)) + +#define JRI_IsSubclassOf(env, a, b) \ + (((*(env))->IsSubclassOf)(env, JRI_IsSubclassOf_op, a, b)) + +#define JRI_GetStaticMethodID(env, clazz, name, sig) \ + (((*(env))->GetStaticMethodID)(env, JRI_GetStaticMethodID_op, clazz, name, sig)) + +#define JRI_CallStaticMethod(env) ((*(env))->CallStaticMethod) +#define JRI_CallStaticMethodV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodV)(env, JRI_CallStaticMethod_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodA)(env, JRI_CallStaticMethod_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodBoolean(env) ((*(env))->CallStaticMethodBoolean) +#define JRI_CallStaticMethodBooleanV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodBooleanV)(env, JRI_CallStaticMethodBoolean_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodBooleanA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodBooleanA)(env, JRI_CallStaticMethodBoolean_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodByte(env) ((*(env))->CallStaticMethodByte) +#define JRI_CallStaticMethodByteV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodByteV)(env, JRI_CallStaticMethodByte_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodByteA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodByteA)(env, JRI_CallStaticMethodByte_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodChar(env) ((*(env))->CallStaticMethodChar) +#define JRI_CallStaticMethodCharV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodCharV)(env, JRI_CallStaticMethodChar_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodCharA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodCharA)(env, JRI_CallStaticMethodChar_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodShort(env) ((*(env))->CallStaticMethodShort) +#define JRI_CallStaticMethodShortV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodShortV)(env, JRI_CallStaticMethodShort_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodShortA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodShortA)(env, JRI_CallStaticMethodShort_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodInt(env) ((*(env))->CallStaticMethodInt) +#define JRI_CallStaticMethodIntV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodIntV)(env, JRI_CallStaticMethodInt_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodIntA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodIntA)(env, JRI_CallStaticMethodInt_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodLong(env) ((*(env))->CallStaticMethodLong) +#define JRI_CallStaticMethodLongV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodLongV)(env, JRI_CallStaticMethodLong_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodLongA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodLongA)(env, JRI_CallStaticMethodLong_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodFloat(env) ((*(env))->CallStaticMethodFloat) +#define JRI_CallStaticMethodFloatV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodFloatV)(env, JRI_CallStaticMethodFloat_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodFloatA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodFloatA)(env, JRI_CallStaticMethodFloat_op_array, clazz, methodID, args)) + +#define JRI_CallStaticMethodDouble(env) ((*(env))->CallStaticMethodDouble) +#define JRI_CallStaticMethodDoubleV(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodDoubleV)(env, JRI_CallStaticMethodDouble_op_va_list, clazz, methodID, args)) +#define JRI_CallStaticMethodDoubleA(env, clazz, methodID, args) \ + (((*(env))->CallStaticMethodDoubleA)(env, JRI_CallStaticMethodDouble_op_array, clazz, methodID, args)) + +#define JRI_GetStaticFieldID(env, clazz, name, sig) \ + (((*(env))->GetStaticFieldID)(env, JRI_GetStaticFieldID_op, clazz, name, sig)) + +#define JRI_GetStaticField(env, clazz, fieldID) \ + (((*(env))->GetStaticField)(env, JRI_GetStaticField_op, clazz, fieldID)) + +#define JRI_GetStaticFieldBoolean(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldBoolean)(env, JRI_GetStaticFieldBoolean_op, clazz, fieldID)) + +#define JRI_GetStaticFieldByte(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldByte)(env, JRI_GetStaticFieldByte_op, clazz, fieldID)) + +#define JRI_GetStaticFieldChar(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldChar)(env, JRI_GetStaticFieldChar_op, clazz, fieldID)) + +#define JRI_GetStaticFieldShort(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldShort)(env, JRI_GetStaticFieldShort_op, clazz, fieldID)) + +#define JRI_GetStaticFieldInt(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldInt)(env, JRI_GetStaticFieldInt_op, clazz, fieldID)) + +#define JRI_GetStaticFieldLong(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldLong)(env, JRI_GetStaticFieldLong_op, clazz, fieldID)) + +#define JRI_GetStaticFieldFloat(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldFloat)(env, JRI_GetStaticFieldFloat_op, clazz, fieldID)) + +#define JRI_GetStaticFieldDouble(env, clazz, fieldID) \ + (((*(env))->GetStaticFieldDouble)(env, JRI_GetStaticFieldDouble_op, clazz, fieldID)) + +#define JRI_SetStaticField(env, clazz, fieldID, value) \ + (((*(env))->SetStaticField)(env, JRI_SetStaticField_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldBoolean(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldBoolean)(env, JRI_SetStaticFieldBoolean_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldByte(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldByte)(env, JRI_SetStaticFieldByte_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldChar(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldChar)(env, JRI_SetStaticFieldChar_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldShort(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldShort)(env, JRI_SetStaticFieldShort_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldInt(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldInt)(env, JRI_SetStaticFieldInt_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldLong(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldLong)(env, JRI_SetStaticFieldLong_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldFloat(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldFloat)(env, JRI_SetStaticFieldFloat_op, clazz, fieldID, value)) + +#define JRI_SetStaticFieldDouble(env, clazz, fieldID, value) \ + (((*(env))->SetStaticFieldDouble)(env, JRI_SetStaticFieldDouble_op, clazz, fieldID, value)) + +#define JRI_NewString(env, unicode, len) \ + (((*(env))->NewString)(env, JRI_NewString_op, unicode, len)) + +#define JRI_GetStringLength(env, string) \ + (((*(env))->GetStringLength)(env, JRI_GetStringLength_op, string)) + +#define JRI_GetStringChars(env, string) \ + (((*(env))->GetStringChars)(env, JRI_GetStringChars_op, string)) + +#define JRI_NewStringUTF(env, utf, len) \ + (((*(env))->NewStringUTF)(env, JRI_NewStringUTF_op, utf, len)) + +#define JRI_GetStringUTFLength(env, string) \ + (((*(env))->GetStringUTFLength)(env, JRI_GetStringUTFLength_op, string)) + +#define JRI_GetStringUTFChars(env, string) \ + (((*(env))->GetStringUTFChars)(env, JRI_GetStringUTFChars_op, string)) + +#define JRI_NewScalarArray(env, length, elementSig, initialElements) \ + (((*(env))->NewScalarArray)(env, JRI_NewScalarArray_op, length, elementSig, initialElements)) + +#define JRI_GetScalarArrayLength(env, array) \ + (((*(env))->GetScalarArrayLength)(env, JRI_GetScalarArrayLength_op, array)) + +#define JRI_GetScalarArrayElements(env, array) \ + (((*(env))->GetScalarArrayElements)(env, JRI_GetScalarArrayElements_op, array)) + +#define JRI_NewObjectArray(env, length, elementClass, initialElement) \ + (((*(env))->NewObjectArray)(env, JRI_NewObjectArray_op, length, elementClass, initialElement)) + +#define JRI_GetObjectArrayLength(env, array) \ + (((*(env))->GetObjectArrayLength)(env, JRI_GetObjectArrayLength_op, array)) + +#define JRI_GetObjectArrayElement(env, array, index) \ + (((*(env))->GetObjectArrayElement)(env, JRI_GetObjectArrayElement_op, array, index)) + +#define JRI_SetObjectArrayElement(env, array, index, value) \ + (((*(env))->SetObjectArrayElement)(env, JRI_SetObjectArrayElement_op, array, index, value)) + +#define JRI_RegisterNatives(env, clazz, nameAndSigArray, nativeProcArray) \ + (((*(env))->RegisterNatives)(env, JRI_RegisterNatives_op, clazz, nameAndSigArray, nativeProcArray)) + +#define JRI_UnregisterNatives(env, clazz) \ + (((*(env))->UnregisterNatives)(env, JRI_UnregisterNatives_op, clazz)) + +#define JRI_NewStringPlatform(env, string, len, encoding, encodingLength) \ + (((*(env))->NewStringPlatform)(env, JRI_NewStringPlatform_op, string, len, encoding, encodingLength)) + +#define JRI_GetStringPlatformChars(env, string, encoding, encodingLength) \ + (((*(env))->GetStringPlatformChars)(env, JRI_GetStringPlatformChars_op, string, encoding, encodingLength)) + + +/******************************************************************************* + * JRIEnv Interface + ******************************************************************************/ + +struct java_lang_ClassLoader; +struct java_lang_Class; +struct java_lang_Throwable; +struct java_lang_Object; +struct java_lang_String; + +struct JRIEnvInterface { + void* reserved0; + void* reserved1; + void* reserved2; + void* reserved3; + struct java_lang_Class* (*FindClass)(JRIEnv* env, jint op, const char* a); + void (*Throw)(JRIEnv* env, jint op, struct java_lang_Throwable* a); + void (*ThrowNew)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b); + struct java_lang_Throwable* (*ExceptionOccurred)(JRIEnv* env, jint op); + void (*ExceptionDescribe)(JRIEnv* env, jint op); + void (*ExceptionClear)(JRIEnv* env, jint op); + jglobal (*NewGlobalRef)(JRIEnv* env, jint op, void* a); + void (*DisposeGlobalRef)(JRIEnv* env, jint op, jglobal a); + void* (*GetGlobalRef)(JRIEnv* env, jint op, jglobal a); + void (*SetGlobalRef)(JRIEnv* env, jint op, jglobal a, void* b); + jbool (*IsSameObject)(JRIEnv* env, jint op, void* a, void* b); + void* (*NewObject)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + void* (*NewObjectV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + void* (*NewObjectA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + struct java_lang_Class* (*GetObjectClass)(JRIEnv* env, jint op, void* a); + jbool (*IsInstanceOf)(JRIEnv* env, jint op, void* a, struct java_lang_Class* b); + jint (*GetMethodID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c); + void* (*CallMethod)(JRIEnv* env, jint op, void* a, jint b, ...); + void* (*CallMethodV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + void* (*CallMethodA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jbool (*CallMethodBoolean)(JRIEnv* env, jint op, void* a, jint b, ...); + jbool (*CallMethodBooleanV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jbool (*CallMethodBooleanA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jbyte (*CallMethodByte)(JRIEnv* env, jint op, void* a, jint b, ...); + jbyte (*CallMethodByteV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jbyte (*CallMethodByteA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jchar (*CallMethodChar)(JRIEnv* env, jint op, void* a, jint b, ...); + jchar (*CallMethodCharV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jchar (*CallMethodCharA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jshort (*CallMethodShort)(JRIEnv* env, jint op, void* a, jint b, ...); + jshort (*CallMethodShortV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jshort (*CallMethodShortA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jint (*CallMethodInt)(JRIEnv* env, jint op, void* a, jint b, ...); + jint (*CallMethodIntV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jint (*CallMethodIntA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jlong (*CallMethodLong)(JRIEnv* env, jint op, void* a, jint b, ...); + jlong (*CallMethodLongV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jlong (*CallMethodLongA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jfloat (*CallMethodFloat)(JRIEnv* env, jint op, void* a, jint b, ...); + jfloat (*CallMethodFloatV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jfloat (*CallMethodFloatA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jdouble (*CallMethodDouble)(JRIEnv* env, jint op, void* a, jint b, ...); + jdouble (*CallMethodDoubleV)(JRIEnv* env, jint op, void* a, jint b, va_list c); + jdouble (*CallMethodDoubleA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c); + jint (*GetFieldID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c); + void* (*GetField)(JRIEnv* env, jint op, void* a, jint b); + jbool (*GetFieldBoolean)(JRIEnv* env, jint op, void* a, jint b); + jbyte (*GetFieldByte)(JRIEnv* env, jint op, void* a, jint b); + jchar (*GetFieldChar)(JRIEnv* env, jint op, void* a, jint b); + jshort (*GetFieldShort)(JRIEnv* env, jint op, void* a, jint b); + jint (*GetFieldInt)(JRIEnv* env, jint op, void* a, jint b); + jlong (*GetFieldLong)(JRIEnv* env, jint op, void* a, jint b); + jfloat (*GetFieldFloat)(JRIEnv* env, jint op, void* a, jint b); + jdouble (*GetFieldDouble)(JRIEnv* env, jint op, void* a, jint b); + void (*SetField)(JRIEnv* env, jint op, void* a, jint b, void* c); + void (*SetFieldBoolean)(JRIEnv* env, jint op, void* a, jint b, jbool c); + void (*SetFieldByte)(JRIEnv* env, jint op, void* a, jint b, jbyte c); + void (*SetFieldChar)(JRIEnv* env, jint op, void* a, jint b, jchar c); + void (*SetFieldShort)(JRIEnv* env, jint op, void* a, jint b, jshort c); + void (*SetFieldInt)(JRIEnv* env, jint op, void* a, jint b, jint c); + void (*SetFieldLong)(JRIEnv* env, jint op, void* a, jint b, jlong c); + void (*SetFieldFloat)(JRIEnv* env, jint op, void* a, jint b, jfloat c); + void (*SetFieldDouble)(JRIEnv* env, jint op, void* a, jint b, jdouble c); + jbool (*IsSubclassOf)(JRIEnv* env, jint op, struct java_lang_Class* a, struct java_lang_Class* b); + jint (*GetStaticMethodID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c); + void* (*CallStaticMethod)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + void* (*CallStaticMethodV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + void* (*CallStaticMethodA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jbool (*CallStaticMethodBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jbool (*CallStaticMethodBooleanV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jbool (*CallStaticMethodBooleanA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jbyte (*CallStaticMethodByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jbyte (*CallStaticMethodByteV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jbyte (*CallStaticMethodByteA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jchar (*CallStaticMethodChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jchar (*CallStaticMethodCharV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jchar (*CallStaticMethodCharA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jshort (*CallStaticMethodShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jshort (*CallStaticMethodShortV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jshort (*CallStaticMethodShortA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jint (*CallStaticMethodInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jint (*CallStaticMethodIntV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jint (*CallStaticMethodIntA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jlong (*CallStaticMethodLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jlong (*CallStaticMethodLongV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jlong (*CallStaticMethodLongA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jfloat (*CallStaticMethodFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jfloat (*CallStaticMethodFloatV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jfloat (*CallStaticMethodFloatA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jdouble (*CallStaticMethodDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...); + jdouble (*CallStaticMethodDoubleV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c); + jdouble (*CallStaticMethodDoubleA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c); + jint (*GetStaticFieldID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c); + void* (*GetStaticField)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jbool (*GetStaticFieldBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jbyte (*GetStaticFieldByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jchar (*GetStaticFieldChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jshort (*GetStaticFieldShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jint (*GetStaticFieldInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jlong (*GetStaticFieldLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jfloat (*GetStaticFieldFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + jdouble (*GetStaticFieldDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b); + void (*SetStaticField)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, void* c); + void (*SetStaticFieldBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jbool c); + void (*SetStaticFieldByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jbyte c); + void (*SetStaticFieldChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jchar c); + void (*SetStaticFieldShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jshort c); + void (*SetStaticFieldInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jint c); + void (*SetStaticFieldLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jlong c); + void (*SetStaticFieldFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jfloat c); + void (*SetStaticFieldDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jdouble c); + struct java_lang_String* (*NewString)(JRIEnv* env, jint op, const jchar* a, jint b); + jint (*GetStringLength)(JRIEnv* env, jint op, struct java_lang_String* a); + const jchar* (*GetStringChars)(JRIEnv* env, jint op, struct java_lang_String* a); + struct java_lang_String* (*NewStringUTF)(JRIEnv* env, jint op, const jbyte* a, jint b); + jint (*GetStringUTFLength)(JRIEnv* env, jint op, struct java_lang_String* a); + const jbyte* (*GetStringUTFChars)(JRIEnv* env, jint op, struct java_lang_String* a); + void* (*NewScalarArray)(JRIEnv* env, jint op, jint a, const char* b, const jbyte* c); + jint (*GetScalarArrayLength)(JRIEnv* env, jint op, void* a); + jbyte* (*GetScalarArrayElements)(JRIEnv* env, jint op, void* a); + void* (*NewObjectArray)(JRIEnv* env, jint op, jint a, struct java_lang_Class* b, void* c); + jint (*GetObjectArrayLength)(JRIEnv* env, jint op, void* a); + void* (*GetObjectArrayElement)(JRIEnv* env, jint op, void* a, jint b); + void (*SetObjectArrayElement)(JRIEnv* env, jint op, void* a, jint b, void* c); + void (*RegisterNatives)(JRIEnv* env, jint op, struct java_lang_Class* a, char** b, void** c); + void (*UnregisterNatives)(JRIEnv* env, jint op, struct java_lang_Class* a); + struct java_lang_Class* (*DefineClass)(JRIEnv* env, jint op, struct java_lang_ClassLoader* a, jbyte* b, jsize bLen); + struct java_lang_String* (*NewStringPlatform)(JRIEnv* env, jint op, const jbyte* a, jint b, const jbyte* c, jint d); + const jbyte* (*GetStringPlatformChars)(JRIEnv* env, jint op, struct java_lang_String* a, const jbyte* b, jint c); +}; + +/* +** **************************************************************************** +** JRIEnv Operation IDs +** *************************************************************************** +*/ + +typedef enum JRIEnvOperations { + JRI_Reserved0_op, + JRI_Reserved1_op, + JRI_Reserved2_op, + JRI_Reserved3_op, + JRI_FindClass_op, + JRI_Throw_op, + JRI_ThrowNew_op, + JRI_ExceptionOccurred_op, + JRI_ExceptionDescribe_op, + JRI_ExceptionClear_op, + JRI_NewGlobalRef_op, + JRI_DisposeGlobalRef_op, + JRI_GetGlobalRef_op, + JRI_SetGlobalRef_op, + JRI_IsSameObject_op, + JRI_NewObject_op, + JRI_NewObject_op_va_list, + JRI_NewObject_op_array, + JRI_GetObjectClass_op, + JRI_IsInstanceOf_op, + JRI_GetMethodID_op, + JRI_CallMethod_op, + JRI_CallMethod_op_va_list, + JRI_CallMethod_op_array, + JRI_CallMethodBoolean_op, + JRI_CallMethodBoolean_op_va_list, + JRI_CallMethodBoolean_op_array, + JRI_CallMethodByte_op, + JRI_CallMethodByte_op_va_list, + JRI_CallMethodByte_op_array, + JRI_CallMethodChar_op, + JRI_CallMethodChar_op_va_list, + JRI_CallMethodChar_op_array, + JRI_CallMethodShort_op, + JRI_CallMethodShort_op_va_list, + JRI_CallMethodShort_op_array, + JRI_CallMethodInt_op, + JRI_CallMethodInt_op_va_list, + JRI_CallMethodInt_op_array, + JRI_CallMethodLong_op, + JRI_CallMethodLong_op_va_list, + JRI_CallMethodLong_op_array, + JRI_CallMethodFloat_op, + JRI_CallMethodFloat_op_va_list, + JRI_CallMethodFloat_op_array, + JRI_CallMethodDouble_op, + JRI_CallMethodDouble_op_va_list, + JRI_CallMethodDouble_op_array, + JRI_GetFieldID_op, + JRI_GetField_op, + JRI_GetFieldBoolean_op, + JRI_GetFieldByte_op, + JRI_GetFieldChar_op, + JRI_GetFieldShort_op, + JRI_GetFieldInt_op, + JRI_GetFieldLong_op, + JRI_GetFieldFloat_op, + JRI_GetFieldDouble_op, + JRI_SetField_op, + JRI_SetFieldBoolean_op, + JRI_SetFieldByte_op, + JRI_SetFieldChar_op, + JRI_SetFieldShort_op, + JRI_SetFieldInt_op, + JRI_SetFieldLong_op, + JRI_SetFieldFloat_op, + JRI_SetFieldDouble_op, + JRI_IsSubclassOf_op, + JRI_GetStaticMethodID_op, + JRI_CallStaticMethod_op, + JRI_CallStaticMethod_op_va_list, + JRI_CallStaticMethod_op_array, + JRI_CallStaticMethodBoolean_op, + JRI_CallStaticMethodBoolean_op_va_list, + JRI_CallStaticMethodBoolean_op_array, + JRI_CallStaticMethodByte_op, + JRI_CallStaticMethodByte_op_va_list, + JRI_CallStaticMethodByte_op_array, + JRI_CallStaticMethodChar_op, + JRI_CallStaticMethodChar_op_va_list, + JRI_CallStaticMethodChar_op_array, + JRI_CallStaticMethodShort_op, + JRI_CallStaticMethodShort_op_va_list, + JRI_CallStaticMethodShort_op_array, + JRI_CallStaticMethodInt_op, + JRI_CallStaticMethodInt_op_va_list, + JRI_CallStaticMethodInt_op_array, + JRI_CallStaticMethodLong_op, + JRI_CallStaticMethodLong_op_va_list, + JRI_CallStaticMethodLong_op_array, + JRI_CallStaticMethodFloat_op, + JRI_CallStaticMethodFloat_op_va_list, + JRI_CallStaticMethodFloat_op_array, + JRI_CallStaticMethodDouble_op, + JRI_CallStaticMethodDouble_op_va_list, + JRI_CallStaticMethodDouble_op_array, + JRI_GetStaticFieldID_op, + JRI_GetStaticField_op, + JRI_GetStaticFieldBoolean_op, + JRI_GetStaticFieldByte_op, + JRI_GetStaticFieldChar_op, + JRI_GetStaticFieldShort_op, + JRI_GetStaticFieldInt_op, + JRI_GetStaticFieldLong_op, + JRI_GetStaticFieldFloat_op, + JRI_GetStaticFieldDouble_op, + JRI_SetStaticField_op, + JRI_SetStaticFieldBoolean_op, + JRI_SetStaticFieldByte_op, + JRI_SetStaticFieldChar_op, + JRI_SetStaticFieldShort_op, + JRI_SetStaticFieldInt_op, + JRI_SetStaticFieldLong_op, + JRI_SetStaticFieldFloat_op, + JRI_SetStaticFieldDouble_op, + JRI_NewString_op, + JRI_GetStringLength_op, + JRI_GetStringChars_op, + JRI_NewStringUTF_op, + JRI_GetStringUTFLength_op, + JRI_GetStringUTFChars_op, + JRI_NewScalarArray_op, + JRI_GetScalarArrayLength_op, + JRI_GetScalarArrayElements_op, + JRI_NewObjectArray_op, + JRI_GetObjectArrayLength_op, + JRI_GetObjectArrayElement_op, + JRI_SetObjectArrayElement_op, + JRI_RegisterNatives_op, + JRI_UnregisterNatives_op, + JRI_DefineClass_op, + JRI_NewStringPlatform_op, + JRI_GetStringPlatformChars_op +} JRIEnvOperations; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* JRI_H */ +/******************************************************************************/ diff --git a/src/moz-sdk/jri_md.h b/src/moz-sdk/jri_md.h new file mode 100644 index 0000000..2514ec2 --- /dev/null +++ b/src/moz-sdk/jri_md.h @@ -0,0 +1,565 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/******************************************************************************* + * Java Runtime Interface - Machine Dependent Types + ******************************************************************************/ + +#ifndef JRI_MD_H +#define JRI_MD_H + +#include <assert.h> +#include "prtypes.h" /* Needed for HAS_LONG_LONG ifdefs */ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * WHAT'S UP WITH THIS FILE? + * + * This is where we define the mystical JRI_PUBLIC_API macro that works on all + * platforms. If you're running with Visual C++, Symantec C, or Borland's + * development environment on the PC, you're all set. Or if you're on the Mac + * with Metrowerks, Symantec or MPW with SC you're ok too. For UNIX it shouldn't + * matter. + * + * On UNIX though you probably care about a couple of other symbols though: + * IS_LITTLE_ENDIAN must be defined for little-endian systems + * HAVE_LONG_LONG must be defined on systems that have 'long long' integers + * HAVE_ALIGNED_LONGLONGS must be defined if long-longs must be 8 byte aligned + * HAVE_ALIGNED_DOUBLES must be defined if doubles must be 8 byte aligned + * IS_64 must be defined on 64-bit machines (like Dec Alpha) + ******************************************************************************/ + +/* DLL Entry modifiers... */ + +/* PC */ +#if defined(XP_OS2) +# ifdef XP_OS2_VACPP +# define JRI_PUBLIC_API(ResultType) ResultType _Optlink +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_CALLBACK +# else +# define JRI_PUBLIC_API(ResultType) ResultType +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_CALLBACK +# endif +#elif defined(XP_WIN) || defined(_WINDOWS) || defined(WIN32) || defined(_WIN32) +# include <windows.h> +# if defined(_MSC_VER) || defined(__GNUC__) +# if defined(WIN32) || defined(_WIN32) +# define JRI_PUBLIC_API(ResultType) __declspec(dllexport) ResultType +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_PUBLIC_VAR_EXP(VarType) __declspec(dllexport) VarType +# define JRI_PUBLIC_VAR_IMP(VarType) __declspec(dllimport) VarType +# define JRI_NATIVE_STUB(ResultType) __declspec(dllexport) ResultType +# define JRI_CALLBACK +# else /* !_WIN32 */ +# if defined(_WINDLL) +# define JRI_PUBLIC_API(ResultType) ResultType __cdecl __export __loadds +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_PUBLIC_VAR_EXP(VarType) JRI_PUBLIC_VAR(VarType) +# define JRI_PUBLIC_VAR_IMP(VarType) JRI_PUBLIC_VAR(VarType) +# define JRI_NATIVE_STUB(ResultType) ResultType __cdecl __loadds +# define JRI_CALLBACK __loadds +# else /* !WINDLL */ +# define JRI_PUBLIC_API(ResultType) ResultType __cdecl __export +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_PUBLIC_VAR_EXP(VarType) JRI_PUBLIC_VAR(VarType) +# define JRI_PUBLIC_VAR_IMP(VarType) JRI_PUBLIC_VAR(VarType) +# define JRI_NATIVE_STUB(ResultType) ResultType __cdecl __export +# define JRI_CALLBACK __export +# endif /* !WINDLL */ +# endif /* !_WIN32 */ +# elif defined(__BORLANDC__) +# if defined(WIN32) || defined(_WIN32) +# define JRI_PUBLIC_API(ResultType) __export ResultType +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_PUBLIC_VAR_EXP(VarType) __export VarType +# define JRI_PUBLIC_VAR_IMP(VarType) __import VarType +# define JRI_NATIVE_STUB(ResultType) __export ResultType +# define JRI_CALLBACK +# else /* !_WIN32 */ +# define JRI_PUBLIC_API(ResultType) ResultType _cdecl _export _loadds +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_PUBLIC_VAR_EXP(VarType) __cdecl __export VarType +# define JRI_PUBLIC_VAR_IMP(VarType) __cdecl __import VarType +# define JRI_NATIVE_STUB(ResultType) ResultType _cdecl _loadds +# define JRI_CALLBACK _loadds +# endif +# else +# error Unsupported PC development environment. +# endif +# ifndef IS_LITTLE_ENDIAN +# define IS_LITTLE_ENDIAN +# endif + +/* Mac */ +#elif defined (macintosh) || Macintosh || THINK_C +# if defined(__MWERKS__) /* Metrowerks */ +# if !__option(enumsalwaysint) +# error You need to define 'Enums Always Int' for your project. +# endif +# if defined(TARGET_CPU_68K) && !TARGET_RT_MAC_CFM +# if !__option(fourbyteints) +# error You need to define 'Struct Alignment: 68k' for your project. +# endif +# endif /* !GENERATINGCFM */ +# define JRI_PUBLIC_API(ResultType) __declspec(export) ResultType +# define JRI_PUBLIC_VAR(VarType) JRI_PUBLIC_API(VarType) +# define JRI_PUBLIC_VAR_EXP(VarType) JRI_PUBLIC_API(VarType) +# define JRI_PUBLIC_VAR_IMP(VarType) JRI_PUBLIC_API(VarType) +# define JRI_NATIVE_STUB(ResultType) JRI_PUBLIC_API(ResultType) +# elif defined(__SC__) /* Symantec */ +# error What are the Symantec defines? ([email protected]) +# elif macintosh && applec /* MPW */ +# error Please upgrade to the latest MPW compiler (SC). +# else +# error Unsupported Mac development environment. +# endif +# define JRI_CALLBACK + +/* Unix or else */ +#else +# define JRI_PUBLIC_API(ResultType) ResultType +# define JRI_PUBLIC_VAR(VarType) VarType +# define JRI_PUBLIC_VAR_EXP(VarType) JRI_PUBLIC_VAR(VarType) +# define JRI_PUBLIC_VAR_IMP(VarType) JRI_PUBLIC_VAR(VarType) +# define JRI_NATIVE_STUB(ResultType) ResultType +# define JRI_CALLBACK +#endif + +#ifndef FAR /* for non-Win16 */ +#define FAR +#endif + +/******************************************************************************/ + +/* Java Scalar Types */ + +#if 0 /* now in jni.h */ +typedef short jchar; +typedef short jshort; +typedef float jfloat; +typedef double jdouble; +typedef juint jsize; +#endif + +/* moved from jni.h -- Sun's new jni.h doesn't have this anymore */ +#ifdef __cplusplus +typedef class _jobject *jref; +#else +typedef struct _jobject *jref; +#endif + +typedef unsigned char jbool; +typedef signed char jbyte; +#ifdef IS_64 /* XXX ok for alpha, but not right on all 64-bit architectures */ +typedef unsigned int juint; +typedef int jint; +#else +typedef unsigned long juint; +typedef long jint; +#endif + +/******************************************************************************* + * jlong : long long (64-bit signed integer type) support. + ******************************************************************************/ + +/* +** Bit masking macros. (n must be <= 31 to be portable) +*/ +#define JRI_BIT(n) ((juint)1 << (n)) +#define JRI_BITMASK(n) (JRI_BIT(n) - 1) + +#ifdef HAVE_LONG_LONG + +#ifdef OSF1 + +/* long is default 64-bit on OSF1, -std1 does not allow long long */ +typedef long jlong; +typedef unsigned long julong; +#define jlong_MAXINT 0x7fffffffffffffffL +#define jlong_MININT 0x8000000000000000L +#define jlong_ZERO 0x0L + +#elif (defined(WIN32) || defined(_WIN32)) + +typedef LONGLONG jlong; +typedef DWORDLONG julong; +#define jlong_MAXINT 0x7fffffffffffffffi64 +#define jlong_MININT 0x8000000000000000i64 +#define jlong_ZERO 0x0i64 + +#else + +typedef long long jlong; +typedef unsigned long long julong; +#define jlong_MAXINT 0x7fffffffffffffffLL +#define jlong_MININT 0x8000000000000000LL +#define jlong_ZERO 0x0LL + +#endif + +#define jlong_IS_ZERO(a) ((a) == 0) +#define jlong_EQ(a, b) ((a) == (b)) +#define jlong_NE(a, b) ((a) != (b)) +#define jlong_GE_ZERO(a) ((a) >= 0) +#define jlong_CMP(a, op, b) ((a) op (b)) + +#define jlong_AND(r, a, b) ((r) = (a) & (b)) +#define jlong_OR(r, a, b) ((r) = (a) | (b)) +#define jlong_XOR(r, a, b) ((r) = (a) ^ (b)) +#define jlong_OR2(r, a) ((r) = (r) | (a)) +#define jlong_NOT(r, a) ((r) = ~(a)) + +#define jlong_NEG(r, a) ((r) = -(a)) +#define jlong_ADD(r, a, b) ((r) = (a) + (b)) +#define jlong_SUB(r, a, b) ((r) = (a) - (b)) + +#define jlong_MUL(r, a, b) ((r) = (a) * (b)) +#define jlong_DIV(r, a, b) ((r) = (a) / (b)) +#define jlong_MOD(r, a, b) ((r) = (a) % (b)) + +#define jlong_SHL(r, a, b) ((r) = (a) << (b)) +#define jlong_SHR(r, a, b) ((r) = (a) >> (b)) +#define jlong_USHR(r, a, b) ((r) = (julong)(a) >> (b)) +#define jlong_ISHL(r, a, b) ((r) = ((jlong)(a)) << (b)) + +#define jlong_L2I(i, l) ((i) = (int)(l)) +#define jlong_L2UI(ui, l) ((ui) =(unsigned int)(l)) +#define jlong_L2F(f, l) ((f) = (l)) +#define jlong_L2D(d, l) ((d) = (l)) + +#define jlong_I2L(l, i) ((l) = (i)) +#define jlong_UI2L(l, ui) ((l) = (ui)) +#define jlong_F2L(l, f) ((l) = (f)) +#define jlong_D2L(l, d) ((l) = (d)) + +#define jlong_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((julong)(a) / (b)), \ + *(rp) = ((julong)(a) % (b))) + +#else /* !HAVE_LONG_LONG */ + +typedef struct { +#ifdef IS_LITTLE_ENDIAN + juint lo, hi; +#else + juint hi, lo; +#endif +} jlong; +typedef jlong julong; + +extern jlong jlong_MAXINT, jlong_MININT, jlong_ZERO; + +#define jlong_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0)) +#define jlong_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo)) +#define jlong_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo)) +#define jlong_GE_ZERO(a) (((a).hi >> 31) == 0) + +/* + * NB: jlong_CMP and jlong_UCMP work only for strict relationals (<, >). + */ +#define jlong_CMP(a, op, b) (((int32)(a).hi op (int32)(b).hi) || \ + (((a).hi == (b).hi) && ((a).lo op (b).lo))) +#define jlong_UCMP(a, op, b) (((a).hi op (b).hi) || \ + (((a).hi == (b).hi) && ((a).lo op (b).lo))) + +#define jlong_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \ + (r).hi = (a).hi & (b).hi) +#define jlong_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \ + (r).hi = (a).hi | (b).hi) +#define jlong_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \ + (r).hi = (a).hi ^ (b).hi) +#define jlong_OR2(r, a) ((r).lo = (r).lo | (a).lo, \ + (r).hi = (r).hi | (a).hi) +#define jlong_NOT(r, a) ((r).lo = ~(a).lo, \ + (r).hi = ~(a).hi) + +#define jlong_NEG(r, a) ((r).lo = -(int32)(a).lo, \ + (r).hi = -(int32)(a).hi - ((r).lo != 0)) +#define jlong_ADD(r, a, b) { \ + jlong _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo + _b.lo; \ + (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \ +} + +#define jlong_SUB(r, a, b) { \ + jlong _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo - _b.lo; \ + (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \ +} \ + +/* + * Multiply 64-bit operands a and b to get 64-bit result r. + * First multiply the low 32 bits of a and b to get a 64-bit result in r. + * Then add the outer and inner products to r.hi. + */ +#define jlong_MUL(r, a, b) { \ + jlong _a, _b; \ + _a = a; _b = b; \ + jlong_MUL32(r, _a.lo, _b.lo); \ + (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \ +} + +/* XXX _jlong_lo16(a) = ((a) << 16 >> 16) is better on some archs (not on mips) */ +#define _jlong_lo16(a) ((a) & JRI_BITMASK(16)) +#define _jlong_hi16(a) ((a) >> 16) + +/* + * Multiply 32-bit operands a and b to get 64-bit result r. + * Use polynomial expansion based on primitive field element (1 << 16). + */ +#define jlong_MUL32(r, a, b) { \ + juint _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \ + _a1 = _jlong_hi16(a), _a0 = _jlong_lo16(a); \ + _b1 = _jlong_hi16(b), _b0 = _jlong_lo16(b); \ + _y0 = _a0 * _b0; \ + _y1 = _a0 * _b1; \ + _y2 = _a1 * _b0; \ + _y3 = _a1 * _b1; \ + _y1 += _jlong_hi16(_y0); /* can't carry */ \ + _y1 += _y2; /* might carry */ \ + if (_y1 < _y2) _y3 += 1 << 16; /* propagate */ \ + (r).lo = (_jlong_lo16(_y1) << 16) + _jlong_lo16(_y0); \ + (r).hi = _y3 + _jlong_hi16(_y1); \ +} + +/* + * Divide 64-bit unsigned operand a by 64-bit unsigned operand b, setting *qp + * to the 64-bit unsigned quotient, and *rp to the 64-bit unsigned remainder. + * Minimize effort if one of qp and rp is null. + */ +#define jlong_UDIVMOD(qp, rp, a, b) jlong_udivmod(qp, rp, a, b) + +extern JRI_PUBLIC_API(void) +jlong_udivmod(julong *qp, julong *rp, julong a, julong b); + +#define jlong_DIV(r, a, b) { \ + jlong _a, _b; \ + juint _negative = (int32)(a).hi < 0; \ + if (_negative) { \ + jlong_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((int32)(b).hi < 0) { \ + _negative ^= 1; \ + jlong_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + jlong_UDIVMOD(&(r), 0, _a, _b); \ + if (_negative) \ + jlong_NEG(r, r); \ +} + +#define jlong_MOD(r, a, b) { \ + jlong _a, _b; \ + juint _negative = (int32)(a).hi < 0; \ + if (_negative) { \ + jlong_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((int32)(b).hi < 0) { \ + jlong_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + jlong_UDIVMOD(0, &(r), _a, _b); \ + if (_negative) \ + jlong_NEG(r, r); \ +} + +/* + * NB: b is a juint, not jlong or julong, for the shift ops. + */ +#define jlong_SHL(r, a, b) { \ + if (b) { \ + jlong _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = _a.lo << (b); \ + (r).hi = (_a.hi << (b)) | (_a.lo >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = _a.lo << ((b) & 31); \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +/* a is an int32, b is int32, r is jlong */ +#define jlong_ISHL(r, a, b) { \ + if (b) { \ + jlong _a; \ + _a.lo = (a); \ + _a.hi = 0; \ + if ((b) < 32) { \ + (r).lo = (a) << (b); \ + (r).hi = ((a) >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = (a) << ((b) & 31); \ + } \ + } else { \ + (r).lo = (a); \ + (r).hi = 0; \ + } \ +} + +#define jlong_SHR(r, a, b) { \ + if (b) { \ + jlong _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> (b)); \ + (r).hi = (int32)_a.hi >> (b); \ + } else { \ + (r).lo = (int32)_a.hi >> ((b) & 31); \ + (r).hi = (int32)_a.hi >> 31; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define jlong_USHR(r, a, b) { \ + if (b) { \ + jlong _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> (b)); \ + (r).hi = _a.hi >> (b); \ + } else { \ + (r).lo = _a.hi >> ((b) & 31); \ + (r).hi = 0; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define jlong_L2I(i, l) ((i) = (l).lo) +#define jlong_L2UI(ui, l) ((ui) = (l).lo) +#define jlong_L2F(f, l) { double _d; jlong_L2D(_d, l); (f) = (float) _d; } + +#define jlong_L2D(d, l) { \ + int32 _negative; \ + jlong _absval; \ + \ + _negative = (l).hi >> 31; \ + if (_negative) { \ + jlong_NEG(_absval, l); \ + } else { \ + _absval = l; \ + } \ + (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \ + if (_negative) \ + (d) = -(d); \ +} + +#define jlong_I2L(l, i) ((l).hi = (i) >> 31, (l).lo = (i)) +#define jlong_UI2L(l, ui) ((l).hi = 0, (l).lo = (ui)) +#define jlong_F2L(l, f) { double _d = (double) f; jlong_D2L(l, _d); } + +#define jlong_D2L(l, d) { \ + int _negative; \ + double _absval, _d_hi; \ + jlong _lo_d; \ + \ + _negative = ((d) < 0); \ + _absval = _negative ? -(d) : (d); \ + \ + (l).hi = (juint)(_absval / 4.294967296e9); \ + (l).lo = 0; \ + jlong_L2D(_d_hi, l); \ + _absval -= _d_hi; \ + _lo_d.hi = 0; \ + if (_absval < 0) { \ + _lo_d.lo = (juint) -_absval; \ + jlong_SUB(l, l, _lo_d); \ + } else { \ + _lo_d.lo = (juint) _absval; \ + jlong_ADD(l, l, _lo_d); \ + } \ + \ + if (_negative) \ + jlong_NEG(l, l); \ +} + +#endif /* !HAVE_LONG_LONG */ + +/******************************************************************************/ + +#ifdef HAVE_ALIGNED_LONGLONGS +#define JRI_GET_INT64(_t,_addr) ( ((_t).x[0] = ((jint*)(_addr))[0]), \ + ((_t).x[1] = ((jint*)(_addr))[1]), \ + (_t).l ) +#define JRI_SET_INT64(_t, _addr, _v) ( (_t).l = (_v), \ + ((jint*)(_addr))[0] = (_t).x[0], \ + ((jint*)(_addr))[1] = (_t).x[1] ) +#else +#define JRI_GET_INT64(_t,_addr) (*(jlong*)(_addr)) +#define JRI_SET_INT64(_t, _addr, _v) (*(jlong*)(_addr) = (_v)) +#endif + +/* If double's must be aligned on doubleword boundaries then define this */ +#ifdef HAVE_ALIGNED_DOUBLES +#define JRI_GET_DOUBLE(_t,_addr) ( ((_t).x[0] = ((jint*)(_addr))[0]), \ + ((_t).x[1] = ((jint*)(_addr))[1]), \ + (_t).d ) +#define JRI_SET_DOUBLE(_t, _addr, _v) ( (_t).d = (_v), \ + ((jint*)(_addr))[0] = (_t).x[0], \ + ((jint*)(_addr))[1] = (_t).x[1] ) +#else +#define JRI_GET_DOUBLE(_t,_addr) (*(jdouble*)(_addr)) +#define JRI_SET_DOUBLE(_t, _addr, _v) (*(jdouble*)(_addr) = (_v)) +#endif + +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +#endif /* JRI_MD_H */ +/******************************************************************************/ diff --git a/src/moz-sdk/jritypes.h b/src/moz-sdk/jritypes.h new file mode 100644 index 0000000..2ef14ae --- /dev/null +++ b/src/moz-sdk/jritypes.h @@ -0,0 +1,243 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/******************************************************************************* + * Java Runtime Interface + ******************************************************************************/ + +#ifndef JRITYPES_H +#define JRITYPES_H + +#include "jri_md.h" +#include "jni.h" +#include <stddef.h> +#include <stdlib.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * Types + ******************************************************************************/ + +struct JRIEnvInterface; + +typedef void* JRIRef; +typedef void* JRIGlobalRef; + +typedef jint JRIFieldID; +typedef jint JRIMethodID; + +/* synonyms: */ +typedef JRIGlobalRef jglobal; + +typedef union JRIValue { + jbool z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong l; + jfloat f; + jdouble d; + jref r; +} JRIValue; + +typedef enum JRIBoolean { + JRIFalse = 0, + JRITrue = 1 +} JRIBoolean; + +typedef enum JRIConstant { + JRIUninitialized = -1 +} JRIConstant; + +/* convenience types (these must be distinct struct types for c++ overloading): */ +#if 0 /* now in jni.h */ +typedef struct jbooleanArrayStruct* jbooleanArray; +typedef struct jbyteArrayStruct* jbyteArray; +typedef struct jcharArrayStruct* jcharArray; +typedef struct jshortArrayStruct* jshortArray; +typedef struct jintArrayStruct* jintArray; +typedef struct jlongArrayStruct* jlongArray; +typedef struct jfloatArrayStruct* jfloatArray; +typedef struct jdoubleArrayStruct* jdoubleArray; +typedef struct jobjectArrayStruct* jobjectArray; +#endif +typedef struct jstringArrayStruct* jstringArray; +typedef struct jarrayArrayStruct* jarrayArray; + +#define JRIConstructorMethodName "<init>" + +/******************************************************************************* + * Signature Construction Macros + ******************************************************************************/ + +/* +** These macros can be used to construct signature strings. Hopefully their names +** are a little easier to remember than the single character they correspond to. +** For example, to specify the signature of the method: +** +** public int read(byte b[], int off, int len); +** +** you could write something like this in C: +** +** char* readSig = JRISigMethod(JRISigArray(JRISigByte) +** JRISigInt +** JRISigInt) JRISigInt; +** +** Of course, don't put commas between the types. +*/ +#define JRISigArray(T) "[" T +#define JRISigByte "B" +#define JRISigChar "C" +#define JRISigClass(name) "L" name ";" +#define JRISigFloat "F" +#define JRISigDouble "D" +#define JRISigMethod(args) "(" args ")" +#define JRISigNoArgs "" +#define JRISigInt "I" +#define JRISigLong "J" +#define JRISigShort "S" +#define JRISigVoid "V" +#define JRISigBoolean "Z" + +/******************************************************************************* + * Environments + ******************************************************************************/ + +extern JRI_PUBLIC_API(const struct JRIEnvInterface**) +JRI_GetCurrentEnv(void); + +/******************************************************************************* + * Specific Scalar Array Types + ******************************************************************************/ + +/* +** The JRI Native Method Interface does not support boolean arrays. This +** is to allow Java runtime implementations to optimize boolean array +** storage. Using the ScalarArray operations on boolean arrays is bound +** to fail, so convert any boolean arrays to byte arrays in Java before +** passing them to a native method. +*/ + +#define JRI_NewByteArray(env, length, initialValues) \ + JRI_NewScalarArray(env, length, JRISigByte, (jbyte*)(initialValues)) +#define JRI_GetByteArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetByteArrayElements(env, array) \ + JRI_GetScalarArrayElements(env, array) + +#define JRI_NewCharArray(env, length, initialValues) \ + JRI_NewScalarArray(env, ((length) * sizeof(jchar)), JRISigChar, (jbyte*)(initialValues)) +#define JRI_GetCharArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetCharArrayElements(env, array) \ + ((jchar*)JRI_GetScalarArrayElements(env, array)) + +#define JRI_NewShortArray(env, length, initialValues) \ + JRI_NewScalarArray(env, ((length) * sizeof(jshort)), JRISigShort, (jbyte*)(initialValues)) +#define JRI_GetShortArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetShortArrayElements(env, array) \ + ((jshort*)JRI_GetScalarArrayElements(env, array)) + +#define JRI_NewIntArray(env, length, initialValues) \ + JRI_NewScalarArray(env, ((length) * sizeof(jint)), JRISigInt, (jbyte*)(initialValues)) +#define JRI_GetIntArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetIntArrayElements(env, array) \ + ((jint*)JRI_GetScalarArrayElements(env, array)) + +#define JRI_NewLongArray(env, length, initialValues) \ + JRI_NewScalarArray(env, ((length) * sizeof(jlong)), JRISigLong, (jbyte*)(initialValues)) +#define JRI_GetLongArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetLongArrayElements(env, array) \ + ((jlong*)JRI_GetScalarArrayElements(env, array)) + +#define JRI_NewFloatArray(env, length, initialValues) \ + JRI_NewScalarArray(env, ((length) * sizeof(jfloat)), JRISigFloat, (jbyte*)(initialValues)) +#define JRI_GetFloatArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetFloatArrayElements(env, array) \ + ((jfloat*)JRI_GetScalarArrayElements(env, array)) + +#define JRI_NewDoubleArray(env, length, initialValues) \ + JRI_NewScalarArray(env, ((length) * sizeof(jdouble)), JRISigDouble, (jbyte*)(initialValues)) +#define JRI_GetDoubleArrayLength(env, array) \ + JRI_GetScalarArrayLength(env, array) +#define JRI_GetDoubleArrayElements(env, array) \ + ((jdouble*)JRI_GetScalarArrayElements(env, array)) + +/******************************************************************************/ +/* +** JDK Stuff -- This stuff is still needed while we're using the JDK +** dynamic linking strategy to call native methods. +*/ + +typedef union JRI_JDK_stack_item { + /* Non pointer items */ + jint i; + jfloat f; + jint o; + /* Pointer items */ + void *h; + void *p; + unsigned char *addr; +#ifdef IS_64 + double d; + long l; /* == 64bits! */ +#endif +} JRI_JDK_stack_item; + +typedef union JRI_JDK_Java8Str { + jint x[2]; + jdouble d; + jlong l; + void *p; + float f; +} JRI_JDK_Java8; + +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +#endif /* JRITYPES_H */ +/******************************************************************************/ diff --git a/src/moz-sdk/npapi.h b/src/moz-sdk/npapi.h new file mode 100644 index 0000000..6092112 --- /dev/null +++ b/src/moz-sdk/npapi.h @@ -0,0 +1,726 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* + * npapi.h $Revision: 3.40.4.1 $ + * Netscape client plug-in API spec + */ + +#ifndef _NPAPI_H_ +#define _NPAPI_H_ + +#ifdef __OS2__ +#pragma pack(1) +#endif + +#include "prtypes.h" +/* Copied from xp_core.h */ +/* removed #ifdef for hpux defined in /usr/include/model.h */ +#ifndef XP_MAC +#ifndef _INT16 +#define _INT16 +#endif +#ifndef _INT32 +#define _INT32 +#endif +#ifndef _UINT16 +#define _UINT16 +#endif +#ifndef _UINT32 +#define _UINT32 +#endif +#endif + +/* + * NO_NSPR_10_SUPPORT disables the inclusion + * of obsolete/protypes.h, whose int16, uint16, + * int32, and uint32 typedefs conflict with those + * in this file. + */ +#ifndef NO_NSPR_10_SUPPORT +#define NO_NSPR_10_SUPPORT +#endif +#ifdef OJI +#include "jri.h" /* Java Runtime Interface */ +#endif + +#if defined (__OS2__ ) || defined (OS2) +# ifndef XP_OS2 +# define XP_OS2 1 +# endif /* XP_OS2 */ +#endif /* __OS2__ */ + +#ifdef _WINDOWS +# include <windef.h> +# ifndef XP_WIN +# define XP_WIN 1 +# endif /* XP_WIN */ +#endif /* _WINDOWS */ + +#ifdef __MWERKS__ +# define _declspec __declspec +# ifdef macintosh +# ifndef XP_MAC +# define XP_MAC 1 +# endif /* XP_MAC */ +# endif /* macintosh */ +# ifdef __INTEL__ +# undef NULL +# ifndef XP_WIN +# define XP_WIN 1 +# endif /* XP_WIN */ +# endif /* __INTEL__ */ +#endif /* __MWERKS__ */ + +#if defined(XP_MAC) || defined(XP_MACOSX) + #include <Quickdraw.h> + #include <Events.h> +#endif + +#if defined(XP_UNIX) +# include <stdio.h> +# if defined(MOZ_X11) +# include <X11/Xlib.h> +# include <X11/Xutil.h> +# endif +#endif + +/*----------------------------------------------------------------------*/ +/* Plugin Version Constants */ +/*----------------------------------------------------------------------*/ + +#define NP_VERSION_MAJOR 0 +#define NP_VERSION_MINOR 16 + + +/* The OS/2 version of Netscape uses RC_DATA to define the + mime types, file extensions, etc that are required. + Use a vertical bar to separate types, end types with \0. + FileVersion and ProductVersion are 32bit ints, all other + entries are strings the MUST be terminated wwith a \0. + +AN EXAMPLE: + +RCDATA NP_INFO_ProductVersion { 1,0,0,1,} + +RCDATA NP_INFO_MIMEType { "video/x-video|", + "video/x-flick\0" } +RCDATA NP_INFO_FileExtents { "avi|", + "flc\0" } +RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|", + "MMOS2 Flc/Fli player(*.flc)\0" } + +RCDATA NP_INFO_FileVersion { 1,0,0,1 } +RCDATA NP_INFO_CompanyName { "Netscape Communications\0" } +RCDATA NP_INFO_FileDescription { "NPAVI32 Extension DLL\0" +RCDATA NP_INFO_InternalName { "NPAVI32\0" ) +RCDATA NP_INFO_LegalCopyright { "Copyright Netscape Communications \251 1996\0" +RCDATA NP_INFO_OriginalFilename { "NVAPI32.DLL" } +RCDATA NP_INFO_ProductName { "NPAVI32 Dynamic Link Library\0" } + +*/ + + +/* RC_DATA types for version info - required */ +#define NP_INFO_ProductVersion 1 +#define NP_INFO_MIMEType 2 +#define NP_INFO_FileOpenName 3 +#define NP_INFO_FileExtents 4 + +/* RC_DATA types for version info - used if found */ +#define NP_INFO_FileDescription 5 +#define NP_INFO_ProductName 6 + +/* RC_DATA types for version info - optional */ +#define NP_INFO_CompanyName 7 +#define NP_INFO_FileVersion 8 +#define NP_INFO_InternalName 9 +#define NP_INFO_LegalCopyright 10 +#define NP_INFO_OriginalFilename 11 + +#ifndef RC_INVOKED + + + +/*----------------------------------------------------------------------*/ +/* Definition of Basic Types */ +/*----------------------------------------------------------------------*/ + +#ifndef _UINT16 +typedef unsigned short uint16; +#endif + +#ifndef _UINT32 +# if defined(__alpha) || defined(__amd64__) || defined(__x86_64__) +typedef unsigned int uint32; +# else /* __alpha */ +typedef unsigned long uint32; +# endif /* __alpha */ +#endif + +/* + * AIX defines these in sys/inttypes.h included from sys/types.h + */ +#ifndef AIX +#ifndef _INT16 +typedef short int16; +#endif + +#ifndef _INT32 +# if defined(__alpha) || defined(__amd64__) || defined(__x86_64__) +typedef int int32; +# else /* __alpha */ +typedef long int32; +# endif /* __alpha */ +#endif +#endif + +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif +#ifndef NULL +#define NULL (0L) +#endif + +typedef unsigned char NPBool; +typedef int16 NPError; +typedef int16 NPReason; +typedef char* NPMIMEType; + + + +/*----------------------------------------------------------------------*/ +/* Structures and definitions */ +/*----------------------------------------------------------------------*/ + +#ifdef XP_MAC +#pragma options align=mac68k +#endif + +/* + * NPP is a plug-in's opaque instance handle + */ +typedef struct _NPP +{ + void* pdata; /* plug-in private data */ + void* ndata; /* netscape private data */ +} NPP_t; + +typedef NPP_t* NPP; + + +typedef struct _NPStream +{ + void* pdata; /* plug-in private data */ + void* ndata; /* netscape private data */ + const char* url; + uint32 end; + uint32 lastmodified; + void* notifyData; +} NPStream; + + +typedef struct _NPByteRange +{ + int32 offset; /* negative offset means from the end */ + uint32 length; + struct _NPByteRange* next; +} NPByteRange; + + +typedef struct _NPSavedData +{ + int32 len; + void* buf; +} NPSavedData; + + +typedef struct _NPRect +{ + uint16 top; + uint16 left; + uint16 bottom; + uint16 right; +} NPRect; + +typedef struct _NPSize +{ + int32 width; + int32 height; +} NPSize; + +#ifdef XP_UNIX +/* + * Unix specific structures and definitions + */ + +/* + * Callback Structures. + * + * These are used to pass additional platform specific information. + */ +enum { + NP_SETWINDOW = 1, + NP_PRINT +}; + +typedef struct +{ + int32 type; +} NPAnyCallbackStruct; + +typedef struct +{ + int32 type; +#ifdef MOZ_X11 + Display* display; + Visual* visual; + Colormap colormap; + unsigned int depth; +#endif +} NPSetWindowCallbackStruct; + +typedef struct +{ + int32 type; + FILE* fp; +} NPPrintCallbackStruct; + +#endif /* XP_UNIX */ + + +/* + * The following masks are applied on certain platforms to NPNV and + * NPPV selectors that pass around pointers to COM interfaces. Newer + * compilers on some platforms may generate vtables that are not + * compatible with older compilers. To prevent older plugins from + * not understanding a new browser's ABI, these masks change the + * values of those selectors on those platforms. To remain backwards + * compatible with differenet versions of the browser, plugins can + * use these masks to dynamically determine and use the correct C++ + * ABI that the browser is expecting. This does not apply to Windows + * as Microsoft's COM ABI will likely not change. + */ + +#define NP_ABI_GCC3_MASK 0x10000000 +/* + * gcc 3.x generated vtables on UNIX and OSX are incompatible with + * previous compilers. + */ +#if (defined (XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3)) +#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK +#else +#define _NP_ABI_MIXIN_FOR_GCC3 0 +#endif + + +#define NP_ABI_MACHO_MASK 0x01000000 +/* + * On OSX, the Mach-O executable format is significantly + * different than CFM. In addition to having a different + * C++ ABI, it also has has different C calling convention. + * You must use glue code when calling between CFM and + * Mach-O C functions. + */ +#if (defined(TARGET_RT_MAC_MACHO)) +#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK +#else +#define _NP_ABI_MIXIN_FOR_MACHO 0 +#endif + + +#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO) + +/* + * List of variable names for which NPP_GetValue shall be implemented + */ +typedef enum { + NPPVpluginNameString = 1, + NPPVpluginDescriptionString, + NPPVpluginWindowBool, + NPPVpluginTransparentBool, + NPPVjavaClass, /* Not implemented in Mozilla 1.0 */ + NPPVpluginWindowSize, + NPPVpluginTimerInterval, + + NPPVpluginScriptableInstance = (10 | NP_ABI_MASK), + NPPVpluginScriptableIID = 11, + + /* Introduced in Mozilla 0.9.9 */ + NPPVjavascriptPushCallerBool = 12, + + /* Introduced in Mozilla 1.0 */ + NPPVpluginKeepLibraryInMemory = 13, + NPPVpluginNeedsXEmbed = 14, + + /* Get the NPObject for scripting the plugin. Introduced in Firefox + * 1.0 (NPAPI minor version 14). + */ + NPPVpluginScriptableNPObject = 15, + + /* Get the plugin value (as \0-terminated UTF-8 string data) for + * form submission if the plugin is part of a form. Use + * NPN_MemAlloc() to allocate memory for the string data. Introduced + * in Mozilla 1.8b2 (NPAPI minor version 15). + */ + NPPVformValue = 16 +} NPPVariable; + +/* + * List of variable names for which NPN_GetValue is implemented by Mozilla + */ +typedef enum { + NPNVxDisplay = 1, + NPNVxtAppContext, + NPNVnetscapeWindow, + NPNVjavascriptEnabledBool, + NPNVasdEnabledBool, + NPNVisOfflineBool, + + /* 10 and over are available on Mozilla builds starting with 0.9.4 */ + NPNVserviceManager = (10 | NP_ABI_MASK), + NPNVDOMElement = (11 | NP_ABI_MASK), /* available in Mozilla 1.2 */ + NPNVDOMWindow = (12 | NP_ABI_MASK), + NPNVToolkit = (13 | NP_ABI_MASK), + NPNVSupportsXEmbedBool = 14, + + /* Get the NPObject wrapper for the browser window. */ + NPNVWindowNPObject = 15, + + /* Get the NPObject wrapper for the plugins DOM element. */ + NPNVPluginElementNPObject = 16 +} NPNVariable; + +/* + * The type of Tookkit the widgets use + */ +typedef enum { + NPNVGtk12 = 1, + NPNVGtk2 +} NPNToolkitType; + +/* + * The type of a NPWindow - it specifies the type of the data structure + * returned in the window field. + */ +typedef enum { + NPWindowTypeWindow = 1, + NPWindowTypeDrawable +} NPWindowType; + +typedef struct _NPWindow +{ + void* window; /* Platform specific window handle */ + /* OS/2: x - Position of bottom left corner */ + /* OS/2: y - relative to visible netscape window */ + int32 x; /* Position of top left corner relative */ + int32 y; /* to a netscape page. */ + uint32 width; /* Maximum window size */ + uint32 height; + NPRect clipRect; /* Clipping rectangle in port coordinates */ + /* Used by MAC only. */ +#if defined(XP_UNIX) && !defined(XP_MACOSX) + void * ws_info; /* Platform-dependent additonal data */ +#endif /* XP_UNIX */ + NPWindowType type; /* Is this a window or a drawable? */ +} NPWindow; + + +typedef struct _NPFullPrint +{ + NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */ + NPBool printOne; /* TRUE if plugin should print one copy to default printer */ + void* platformPrint; /* Platform-specific printing info */ +} NPFullPrint; + +typedef struct _NPEmbedPrint +{ + NPWindow window; + void* platformPrint; /* Platform-specific printing info */ +} NPEmbedPrint; + +typedef struct _NPPrint +{ + uint16 mode; /* NP_FULL or NP_EMBED */ + union + { + NPFullPrint fullPrint; /* if mode is NP_FULL */ + NPEmbedPrint embedPrint; /* if mode is NP_EMBED */ + } print; +} NPPrint; + +#if defined(XP_MAC) || defined(XP_MACOSX) +typedef EventRecord NPEvent; +#elif defined(XP_WIN) +typedef struct _NPEvent +{ + uint16 event; + uint32 wParam; + uint32 lParam; +} NPEvent; +#elif defined(XP_OS2) +typedef struct _NPEvent +{ + uint32 event; + uint32 wParam; + uint32 lParam; +} NPEvent; +#elif defined (XP_UNIX) && defined(MOZ_X11) +typedef XEvent NPEvent; +#else +typedef void* NPEvent; +#endif /* XP_MAC */ + +#if defined(XP_MAC) || defined(XP_MACOSX) +typedef RgnHandle NPRegion; +#elif defined(XP_WIN) +typedef HRGN NPRegion; +#elif defined(XP_UNIX) && defined(MOZ_X11) +typedef Region NPRegion; +#else +typedef void *NPRegion; +#endif /* XP_MAC */ + +#if defined(XP_MAC) || defined(XP_MACOSX) +/* + * Mac-specific structures and definitions. + */ + +typedef struct NP_Port +{ + CGrafPtr port; /* Grafport */ + int32 portx; /* position inside the topmost window */ + int32 porty; +} NP_Port; + +/* + * Non-standard event types that can be passed to HandleEvent + */ + +enum NPEventType { + NPEventType_GetFocusEvent = (osEvt + 16), + NPEventType_LoseFocusEvent, + NPEventType_AdjustCursorEvent, + NPEventType_MenuCommandEvent, + NPEventType_ClippingChangedEvent, + NPEventType_ScrollingBeginsEvent = 1000, + NPEventType_ScrollingEndsEvent +}; + +#ifdef OBSOLETE +#define getFocusEvent (osEvt + 16) +#define loseFocusEvent (osEvt + 17) +#define adjustCursorEvent (osEvt + 18) +#endif +#endif /* XP_MAC */ + +/* + * Values for mode passed to NPP_New: + */ +#define NP_EMBED 1 +#define NP_FULL 2 + +/* + * Values for stream type passed to NPP_NewStream: + */ +#define NP_NORMAL 1 +#define NP_SEEK 2 +#define NP_ASFILE 3 +#define NP_ASFILEONLY 4 + +#define NP_MAXREADY (((unsigned)(~0)<<1)>>1) + +#ifdef XP_MAC +#pragma options align=reset +#endif + + +/*----------------------------------------------------------------------*/ +/* Error and Reason Code definitions */ +/*----------------------------------------------------------------------*/ + +/* + * Values of type NPError: + */ +#define NPERR_BASE 0 +#define NPERR_NO_ERROR (NPERR_BASE + 0) +#define NPERR_GENERIC_ERROR (NPERR_BASE + 1) +#define NPERR_INVALID_INSTANCE_ERROR (NPERR_BASE + 2) +#define NPERR_INVALID_FUNCTABLE_ERROR (NPERR_BASE + 3) +#define NPERR_MODULE_LOAD_FAILED_ERROR (NPERR_BASE + 4) +#define NPERR_OUT_OF_MEMORY_ERROR (NPERR_BASE + 5) +#define NPERR_INVALID_PLUGIN_ERROR (NPERR_BASE + 6) +#define NPERR_INVALID_PLUGIN_DIR_ERROR (NPERR_BASE + 7) +#define NPERR_INCOMPATIBLE_VERSION_ERROR (NPERR_BASE + 8) +#define NPERR_INVALID_PARAM (NPERR_BASE + 9) +#define NPERR_INVALID_URL (NPERR_BASE + 10) +#define NPERR_FILE_NOT_FOUND (NPERR_BASE + 11) +#define NPERR_NO_DATA (NPERR_BASE + 12) +#define NPERR_STREAM_NOT_SEEKABLE (NPERR_BASE + 13) + +/* + * Values of type NPReason: + */ +#define NPRES_BASE 0 +#define NPRES_DONE (NPRES_BASE + 0) +#define NPRES_NETWORK_ERR (NPRES_BASE + 1) +#define NPRES_USER_BREAK (NPRES_BASE + 2) + +/* + * Don't use these obsolete error codes any more. + */ +#define NP_NOERR NP_NOERR_is_obsolete_use_NPERR_NO_ERROR +#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR +#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK + +/* + * Version feature information + */ +#define NPVERS_HAS_STREAMOUTPUT 8 +#define NPVERS_HAS_NOTIFICATION 9 +#define NPVERS_HAS_LIVECONNECT 9 +#define NPVERS_WIN16_HAS_LIVECONNECT 9 +#define NPVERS_68K_HAS_LIVECONNECT 11 +#define NPVERS_HAS_WINDOWLESS 11 +#define NPVERS_HAS_XPCONNECT_SCRIPTING 13 + +/*----------------------------------------------------------------------*/ +/* Function Prototypes */ +/*----------------------------------------------------------------------*/ + +#if defined(_WINDOWS) && !defined(WIN32) +#define NP_LOADDS _loadds +#else +#if defined(__OS2__) +#define NP_LOADDS _System +#else +#define NP_LOADDS +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * NPP_* functions are provided by the plugin and called by the navigator. + */ + +#ifdef XP_UNIX +char* NPP_GetMIMEDescription(void); +#endif /* XP_UNIX */ + +NPError NP_LOADDS NPP_Initialize(void); +void NP_LOADDS NPP_Shutdown(void); +NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance, + uint16 mode, int16 argc, char* argn[], + char* argv[], NPSavedData* saved); +NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save); +NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window); +NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type, + NPStream* stream, NPBool seekable, + uint16* stype); +NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream, + NPReason reason); +int32 NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream); +int32 NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32 offset, + int32 len, void* buffer); +void NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream, + const char* fname); +void NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint); +int16 NP_LOADDS NPP_HandleEvent(NPP instance, void* event); +void NP_LOADDS NPP_URLNotify(NPP instance, const char* url, + NPReason reason, void* notifyData); +#ifdef OJI +jref NP_LOADDS NPP_GetJavaClass(void); +#endif +NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value); +NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value); + +/* + * NPN_* functions are provided by the navigator and called by the plugin. + */ +void NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor, + int* netscape_major, int* netscape_minor); +NPError NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url, + const char* target, void* notifyData); +NPError NP_LOADDS NPN_GetURL(NPP instance, const char* url, + const char* target); +NPError NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url, + const char* target, uint32 len, + const char* buf, NPBool file, + void* notifyData); +NPError NP_LOADDS NPN_PostURL(NPP instance, const char* url, + const char* target, uint32 len, + const char* buf, NPBool file); +NPError NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList); +NPError NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type, + const char* target, NPStream** stream); +int32 NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer); +NPError NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason); +void NP_LOADDS NPN_Status(NPP instance, const char* message); +const char* NP_LOADDS NPN_UserAgent(NPP instance); +void* NP_LOADDS NPN_MemAlloc(uint32 size); +void NP_LOADDS NPN_MemFree(void* ptr); +uint32 NP_LOADDS NPN_MemFlush(uint32 size); +void NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages); +#ifdef OJI +JRIEnv* NP_LOADDS NPN_GetJavaEnv(void); +jref NP_LOADDS NPN_GetJavaPeer(NPP instance); +#endif +NPError NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable, void *value); +NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, void *value); +void NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect); +void NP_LOADDS NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion); +void NP_LOADDS NPN_ForceRedraw(NPP instance); +void NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled); +void NP_LOADDS NPN_PopPopupsEnabledState(NPP instance); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* RC_INVOKED */ +#ifdef __OS2__ +#pragma pack() +#endif + +#endif /* _NPAPI_H_ */ diff --git a/src/moz-sdk/npruntime.h b/src/moz-sdk/npruntime.h new file mode 100644 index 0000000..2d1dc02 --- /dev/null +++ b/src/moz-sdk/npruntime.h @@ -0,0 +1,397 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright � 2004, Apple Computer, Inc. and The Mozilla Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla + * Foundation ("Mozilla") nor the names of their contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR + * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Revision 1 (March 4, 2004): + * Initial proposal. + * + * Revision 2 (March 10, 2004): + * All calls into script were made asynchronous. Results are + * provided via the NPScriptResultFunctionPtr callback. + * + * Revision 3 (March 10, 2004): + * Corrected comments to not refer to class retain/release FunctionPtrs. + * + * Revision 4 (March 11, 2004): + * Added additional convenience NPN_SetExceptionWithUTF8(). + * Changed NPHasPropertyFunctionPtr and NPHasMethodFunctionPtr to take NPClass + * pointers instead of NPObject pointers. + * Added NPIsValidIdentifier(). + * + * Revision 5 (March 17, 2004): + * Added context parameter to result callbacks from ScriptObject functions. + * + * Revision 6 (March 29, 2004): + * Renamed functions implemented by user agent to NPN_*. Removed _ from + * type names. + * Renamed "JavaScript" types to "Script". + * + * Revision 7 (April 21, 2004): + * NPIdentifier becomes a void*, was int32_t + * Remove NP_IsValidIdentifier, renamed NP_IdentifierFromUTF8 to NP_GetIdentifier + * Added NPVariant and modified functions to use this new type. + * + * Revision 8 (July 9, 2004): + * Updated to joint Apple-Mozilla license. + * + */ +#ifndef _NP_RUNTIME_H_ +#define _NP_RUNTIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "nptypes.h" + +/* + This API is used to facilitate binding code written in C to script + objects. The API in this header does not assume the presence of a + user agent. That is, it can be used to bind C code to scripting + environments outside of the context of a user agent. + + However, the normal use of the this API is in the context of a + scripting environment running in a browser or other user agent. + In particular it is used to support the extended Netscape + script-ability API for plugins (NP-SAP). NP-SAP is an extension + of the Netscape plugin API. As such we have adopted the use of + the "NP" prefix for this API. + + The following NP{N|P}Variables were added to the Netscape plugin + API (in npapi.h): + + NPNVWindowNPObject + NPNVPluginElementNPObject + NPPVpluginScriptableNPObject + + These variables are exposed through NPN_GetValue() and + NPP_GetValue() (respectively) and are used to establish the + initial binding between the user agent and native code. The DOM + objects in the user agent can be examined and manipulated using + the NPN_ functions that operate on NPObjects described in this + header. + + To the extent possible the assumptions about the scripting + language used by the scripting environment have been minimized. +*/ + +#define NP_BEGIN_MACRO do { +#define NP_END_MACRO } while (0) + +/* + Objects (non-primitive data) passed between 'C' and script is + always wrapped in an NPObject. The 'interface' of an NPObject is + described by an NPClass. +*/ +typedef struct NPObject NPObject; +typedef struct NPClass NPClass; + +typedef char NPUTF8; +typedef struct _NPString { + const NPUTF8 *utf8characters; + uint32_t utf8length; +} NPString; + +typedef enum { + NPVariantType_Void, + NPVariantType_Null, + NPVariantType_Bool, + NPVariantType_Int32, + NPVariantType_Double, + NPVariantType_String, + NPVariantType_Object +} NPVariantType; + +typedef struct _NPVariant { + NPVariantType type; + union { + bool boolValue; + uint32_t intValue; + double doubleValue; + NPString stringValue; + NPObject *objectValue; + } value; +} NPVariant; + +/* + NPN_ReleaseVariantValue is called on all 'out' parameters + references. Specifically it is to be called on variants that own + their value, as is the case with all non-const NPVariant* + arguments after a successful call to any methods (except this one) + in this API. + + After calling NPN_ReleaseVariantValue, the type of the variant + will be NPVariantType_Void. +*/ +void NPN_ReleaseVariantValue(NPVariant *variant); + +#define NPVARIANT_IS_VOID(_v) ((_v).type == NPVariantType_Void) +#define NPVARIANT_IS_NULL(_v) ((_v).type == NPVariantType_Null) +#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool) +#define NPVARIANT_IS_INT32(_v) ((_v).type == NPVariantType_Int32) +#define NPVARIANT_IS_DOUBLE(_v) ((_v).type == NPVariantType_Double) +#define NPVARIANT_IS_STRING(_v) ((_v).type == NPVariantType_String) +#define NPVARIANT_IS_OBJECT(_v) ((_v).type == NPVariantType_Object) + +#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue) +#define NPVARIANT_TO_INT32(_v) ((_v).value.intValue) +#define NPVARIANT_TO_DOUBLE(_v) ((_v).value.doubleValue) +#define NPVARIANT_TO_STRING(_v) ((_v).value.stringValue) +#define NPVARIANT_TO_OBJECT(_v) ((_v).value.objectValue) + +#define VOID_TO_NPVARIANT(_v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Void; \ + (_v).value.objectValue = NULL; \ +NP_END_MACRO + +#define NULL_TO_NPVARIANT(_v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Null; \ + (_v).value.objectValue = NULL; \ +NP_END_MACRO + +#define BOOLEAN_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Bool; \ + (_v).value.boolValue = !!(_val); \ +NP_END_MACRO + +#define INT32_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Int32; \ + (_v).value.intValue = _val; \ +NP_END_MACRO + +#define DOUBLE_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Double; \ + (_v).value.doubleValue = _val; \ +NP_END_MACRO + +#define STRINGZ_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_String; \ + NPString str = { _val, strlen(_val) }; \ + (_v).value.stringValue = str; \ +NP_END_MACRO + +#define STRINGN_TO_NPVARIANT(_val, _len, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_String; \ + NPString str = { _val, _len }; \ + (_v).value.stringValue = str; \ +NP_END_MACRO + +#define OBJECT_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Object; \ + (_v).value.objectValue = _val; \ +NP_END_MACRO + + +/* + Type mappings (JavaScript types have been used for illustration + purposes): + + JavaScript to C (NPVariant with type:) + undefined NPVariantType_Void + null NPVariantType_Null + Boolean NPVariantType_Bool + Number NPVariantType_Double or NPVariantType_Int32 + String NPVariantType_String + Object NPVariantType_Object + + C (NPVariant with type:) to JavaScript + NPVariantType_Void undefined + NPVariantType_Null null + NPVariantType_Bool Boolean + NPVariantType_Int32 Number + NPVariantType_Double Number + NPVariantType_String String + NPVariantType_Object Object +*/ + +typedef void *NPIdentifier; + +/* + NPObjects have methods and properties. Methods and properties are + identified with NPIdentifiers. These identifiers may be reflected + in script. NPIdentifiers can be either strings or integers, IOW, + methods and properties can be identified by either strings or + integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be + compared using ==. In case of any errors, the requested + NPIdentifier(s) will be NULL. +*/ +NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name); +void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, + NPIdentifier *identifiers); +NPIdentifier NPN_GetIntIdentifier(int32_t intid); +bool NPN_IdentifierIsString(NPIdentifier identifier); + +/* + The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed. +*/ +NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier); + +/* + Get the integer represented by identifier. If identifier is not an + integer identifier, the behaviour is undefined. +*/ +int32_t NPN_IntFromIdentifier(NPIdentifier identifier); + +/* + NPObject behavior is implemented using the following set of + callback functions. + + The NPVariant *result argument of these functions (where + applicable) should be released using NPN_ReleaseVariantValue(). +*/ +typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass); +typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj); +typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj); +typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name); +typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name, + const NPVariant *args, uint32_t argCount, + NPVariant *result); +typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj, + const NPVariant *args, + uint32_t argCount, + NPVariant *result); +typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name); +typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, + NPVariant *result); +typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, + const NPVariant *value); +typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj, + NPIdentifier name); + +/* + NPObjects returned by create, retain, invoke, and getProperty pass + a reference count to the caller. That is, the callee adds a + reference count which passes to the caller. It is the caller's + responsibility to release the returned object. + + NPInvokeFunctionPtr function may return 0 to indicate a void + result. + + NPInvalidateFunctionPtr is called by the scripting environment + when the native code is shutdown. Any attempt to message a + NPObject instance after the invalidate callback has been + called will result in undefined behavior, even if the native code + is still retaining those NPObject instances. (The runtime + will typically return immediately, with 0 or NULL, from an attempt + to dispatch to a NPObject, but this behavior should not be + depended upon.) +*/ +struct NPClass +{ + uint32_t structVersion; + NPAllocateFunctionPtr allocate; + NPDeallocateFunctionPtr deallocate; + NPInvalidateFunctionPtr invalidate; + NPHasMethodFunctionPtr hasMethod; + NPInvokeFunctionPtr invoke; + NPInvokeDefaultFunctionPtr invokeDefault; + NPHasPropertyFunctionPtr hasProperty; + NPGetPropertyFunctionPtr getProperty; + NPSetPropertyFunctionPtr setProperty; + NPRemovePropertyFunctionPtr removeProperty; +}; + +#define NP_CLASS_STRUCT_VERSION 1 + +struct NPObject { + NPClass *_class; + uint32_t referenceCount; + /* + * Additional space may be allocated here by types of NPObjects + */ +}; + +/* + If the class has an allocate function, NPN_CreateObject invokes + that function, otherwise a NPObject is allocated and + returned. This method will initialize the referenceCount member of + the NPObject to 1. +*/ +NPObject *NPN_CreateObject(NPP npp, NPClass *aClass); + +/* + Increment the NPObject's reference count. +*/ +NPObject *NPN_RetainObject(NPObject *npobj); + +/* + Decremented the NPObject's reference count. If the reference + count goes to zero, the class's destroy function is invoke if + specified, otherwise the object is freed directly. +*/ +void NPN_ReleaseObject(NPObject *npobj); + +/* + Functions to access script objects represented by NPObject. + + Calls to script objects are synchronous. If a function returns a + value, it will be supplied via the result NPVariant + argument. Successful calls will return true, false will be + returned in case of an error. + + Calls made from plugin code to script must be made from the thread + on which the plugin was initialized. +*/ + +bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, + const NPVariant *args, uint32_t argCount, NPVariant *result); +bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, + uint32_t argCount, NPVariant *result); +bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script, + NPVariant *result); +bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, + NPVariant *result); +bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, + const NPVariant *value); +bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); +bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); +bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName); + +/* + NPN_SetException may be called to trigger a script exception upon + return from entry points into NPObjects. Typical usage: + + NPN_SetException (npobj, message); +*/ +void NPN_SetException(NPObject *npobj, const NPUTF8 *message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/moz-sdk/nptypes.h b/src/moz-sdk/nptypes.h new file mode 100644 index 0000000..a05d395 --- /dev/null +++ b/src/moz-sdk/nptypes.h @@ -0,0 +1,105 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * mozilla.org. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Johnny Stenback <[email protected]> (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Header file for ensuring that C99 types ([u]int32_t and bool) are + * available. + */ + +#if defined(WIN32) || defined(OS2) + /* + * Win32 and OS/2 don't know C99, so define [u]int_32 here. The bool + * is predefined tho, both in C and C++. + */ + typedef int int32_t; + typedef unsigned int uint32_t; +#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX) + /* + * AIX and SunOS ship a inttypes.h header that defines [u]int32_t, + * but not bool for C. + */ + #include <inttypes.h> + + #ifndef __cplusplus + typedef int bool; + #endif +#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD) + /* + * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and + * u_int32_t. + */ + #include <sys/types.h> + + /* + * BSD/OS ships no header that defines uint32_t, nor bool (for C) + * OpenBSD ships no header that defines uint32_t and using its bool macro is + * unsafe. + */ + #if defined(bsdi) || defined(OPENBSD) + typedef u_int32_t uint32_t; + + #if !defined(__cplusplus) + typedef int bool; + #endif + #else + /* + * FreeBSD defines uint32_t and bool. + */ + #include <inttypes.h> + #include <stdbool.h> + #endif +#elif defined(BEOS) + #include <inttypes.h> +#else + /* + * For those that ship a standard C99 stdint.h header file, include + * it. Can't do the same for stdbool.h tho, since some systems ship + * with a stdbool.h file that doesn't compile! + */ + #include <stdint.h> + + #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95) + #include <stdbool.h> + #else + /* + * GCC 2.91 can't deal with a typedef for bool, but a #define + * works. + */ + #define bool int + #endif +#endif diff --git a/src/moz-sdk/npupp.h b/src/moz-sdk/npupp.h new file mode 100644 index 0000000..f7e8e5d --- /dev/null +++ b/src/moz-sdk/npupp.h @@ -0,0 +1,1889 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* + * npupp.h $Revision: 3.20 $ + * function call mecahnics needed by platform specific glue code. + */ + + +#ifndef _NPUPP_H_ +#define _NPUPP_H_ + +#if defined(__OS2__) +#pragma pack(1) +#endif + +#ifndef GENERATINGCFM +#define GENERATINGCFM 0 +#endif + +#ifndef _NPAPI_H_ +#include "npapi.h" +#endif + +#include "npruntime.h" + +#include "jri.h" + +/****************************************************************************************** + plug-in function table macros + for each function in and out of the plugin API we define + typedef NPP_FooUPP + #define NewNPP_FooProc + #define CallNPP_FooProc + for mac, define the UPP magic for PPC/68K calling + *******************************************************************************************/ + + +/* NPP_Initialize */ + +#define _NPUPP_USE_UPP_ (TARGET_RT_MAC_CFM && !TARGET_API_MAC_CARBON) + +#if _NPUPP_USE_UPP_ +typedef UniversalProcPtr NPP_InitializeUPP; + +enum { + uppNPP_InitializeProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(0)) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPP_InitializeProc(FUNC) \ + (NPP_InitializeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_InitializeProcInfo, GetCurrentArchitecture()) +#define CallNPP_InitializeProc(FUNC) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_InitializeProcInfo) + +#else + +typedef void (* NP_LOADDS NPP_InitializeUPP)(void); +#define NewNPP_InitializeProc(FUNC) \ + ((NPP_InitializeUPP) (FUNC)) +#define CallNPP_InitializeProc(FUNC) \ + (*(FUNC))() + +#endif + + +/* NPP_Shutdown */ + +#if _NPUPP_USE_UPP_ +typedef UniversalProcPtr NPP_ShutdownUPP; + +enum { + uppNPP_ShutdownProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(0)) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPP_ShutdownProc(FUNC) \ + (NPP_ShutdownUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_ShutdownProcInfo, GetCurrentArchitecture()) +#define CallNPP_ShutdownProc(FUNC) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_ShutdownProcInfo) + +#else + +typedef void (* NP_LOADDS NPP_ShutdownUPP)(void); +#define NewNPP_ShutdownProc(FUNC) \ + ((NPP_ShutdownUPP) (FUNC)) +#define CallNPP_ShutdownProc(FUNC) \ + (*(FUNC))() + +#endif + + +/* NPP_New */ + +#if _NPUPP_USE_UPP_ +typedef UniversalProcPtr NPP_NewUPP; + +enum { + uppNPP_NewProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPMIMEType))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(uint16))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int16))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char **))) + | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(char **))) + | STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(NPSavedData *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; + +#define NewNPP_NewProc(FUNC) \ + (NPP_NewUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_NewProcInfo, GetCurrentArchitecture()) +#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_NewProcInfo, \ + (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) +#else + +typedef NPError (* NP_LOADDS NPP_NewUPP)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); +#define NewNPP_NewProc(FUNC) \ + ((NPP_NewUPP) (FUNC)) +#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) + +#endif + + +/* NPP_Destroy */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_DestroyUPP; +enum { + uppNPP_DestroyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPSavedData **))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_DestroyProc(FUNC) \ + (NPP_DestroyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_DestroyProcInfo, GetCurrentArchitecture()) +#define CallNPP_DestroyProc(FUNC, ARG1, ARG2) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_DestroyProcInfo, (ARG1), (ARG2)) +#else + +typedef NPError (* NP_LOADDS NPP_DestroyUPP)(NPP instance, NPSavedData** save); +#define NewNPP_DestroyProc(FUNC) \ + ((NPP_DestroyUPP) (FUNC)) +#define CallNPP_DestroyProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + + +/* NPP_SetWindow */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_SetWindowUPP; +enum { + uppNPP_SetWindowProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPWindow *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_SetWindowProc(FUNC) \ + (NPP_SetWindowUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_SetWindowProcInfo, GetCurrentArchitecture()) +#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_SetWindowProcInfo, (ARG1), (ARG2)) + +#else + +typedef NPError (* NP_LOADDS NPP_SetWindowUPP)(NPP instance, NPWindow* window); +#define NewNPP_SetWindowProc(FUNC) \ + ((NPP_SetWindowUPP) (FUNC)) +#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + + +/* NPP_NewStream */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_NewStreamUPP; +enum { + uppNPP_NewStreamProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPMIMEType))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPBool))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint16 *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_NewStreamProc(FUNC) \ + (NPP_NewStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_NewStreamProcInfo, GetCurrentArchitecture()) +#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_NewStreamProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) +#else + +typedef NPError (* NP_LOADDS NPP_NewStreamUPP)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); +#define NewNPP_NewStreamProc(FUNC) \ + ((NPP_NewStreamUPP) (FUNC)) +#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) +#endif + + +/* NPP_DestroyStream */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_DestroyStreamUPP; +enum { + uppNPP_DestroyStreamProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_DestroyStreamProc(FUNC) \ + (NPP_DestroyStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_DestroyStreamProcInfo, GetCurrentArchitecture()) +#define CallNPP_DestroyStreamProc(FUNC, NPParg, NPStreamPtr, NPReasonArg) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_DestroyStreamProcInfo, (NPParg), (NPStreamPtr), (NPReasonArg)) + +#else + +typedef NPError (* NP_LOADDS NPP_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason); +#define NewNPP_DestroyStreamProc(FUNC) \ + ((NPP_DestroyStreamUPP) (FUNC)) +#define CallNPP_DestroyStreamProc(FUNC, NPParg, NPStreamPtr, NPReasonArg) \ + (*(FUNC))((NPParg), (NPStreamPtr), (NPReasonArg)) + +#endif + + +/* NPP_WriteReady */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_WriteReadyUPP; +enum { + uppNPP_WriteReadyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *))) + | RESULT_SIZE(SIZE_CODE(sizeof(int32))) +}; +#define NewNPP_WriteReadyProc(FUNC) \ + (NPP_WriteReadyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_WriteReadyProcInfo, GetCurrentArchitecture()) +#define CallNPP_WriteReadyProc(FUNC, NPParg, NPStreamPtr) \ + (int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_WriteReadyProcInfo, (NPParg), (NPStreamPtr)) + +#else + +typedef int32 (* NP_LOADDS NPP_WriteReadyUPP)(NPP instance, NPStream* stream); +#define NewNPP_WriteReadyProc(FUNC) \ + ((NPP_WriteReadyUPP) (FUNC)) +#define CallNPP_WriteReadyProc(FUNC, NPParg, NPStreamPtr) \ + (*(FUNC))((NPParg), (NPStreamPtr)) + +#endif + + +/* NPP_Write */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_WriteUPP; +enum { + uppNPP_WriteProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int32))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int32))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(void*))) + | RESULT_SIZE(SIZE_CODE(sizeof(int32))) +}; +#define NewNPP_WriteProc(FUNC) \ + (NPP_WriteUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_WriteProcInfo, GetCurrentArchitecture()) +#define CallNPP_WriteProc(FUNC, NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr) \ + (int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_WriteProcInfo, (NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr)) + +#else + +typedef int32 (* NP_LOADDS NPP_WriteUPP)(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer); +#define NewNPP_WriteProc(FUNC) \ + ((NPP_WriteUPP) (FUNC)) +#define CallNPP_WriteProc(FUNC, NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr) \ + (*(FUNC))((NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr)) + +#endif + + +/* NPP_StreamAsFile */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_StreamAsFileUPP; +enum { + uppNPP_StreamAsFileProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char *))) + | RESULT_SIZE(SIZE_CODE(0)) +}; +#define NewNPP_StreamAsFileProc(FUNC) \ + (NPP_StreamAsFileUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_StreamAsFileProcInfo, GetCurrentArchitecture()) +#define CallNPP_StreamAsFileProc(FUNC, ARG1, ARG2, ARG3) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_StreamAsFileProcInfo, (ARG1), (ARG2), (ARG3)) + +#else + +typedef void (* NP_LOADDS NPP_StreamAsFileUPP)(NPP instance, NPStream* stream, const char* fname); +#define NewNPP_StreamAsFileProc(FUNC) \ + ((NPP_StreamAsFileUPP) (FUNC)) +#define CallNPP_StreamAsFileProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) +#endif + + +/* NPP_Print */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_PrintUPP; +enum { + uppNPP_PrintProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPrint *))) + | RESULT_SIZE(SIZE_CODE(0)) +}; +#define NewNPP_PrintProc(FUNC) \ + (NPP_PrintUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_PrintProcInfo, GetCurrentArchitecture()) +#define CallNPP_PrintProc(FUNC, NPParg, voidPtr) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_PrintProcInfo, (NPParg), (voidPtr)) + +#else + +typedef void (* NP_LOADDS NPP_PrintUPP)(NPP instance, NPPrint* platformPrint); +#define NewNPP_PrintProc(FUNC) \ + ((NPP_PrintUPP) (FUNC)) +#define CallNPP_PrintProc(FUNC, NPParg, NPPrintArg) \ + (*(FUNC))((NPParg), (NPPrintArg)) + +#endif + + +/* NPP_HandleEvent */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_HandleEventUPP; +enum { + uppNPP_HandleEventProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(void *))) + | RESULT_SIZE(SIZE_CODE(sizeof(int16))) +}; +#define NewNPP_HandleEventProc(FUNC) \ + (NPP_HandleEventUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_HandleEventProcInfo, GetCurrentArchitecture()) +#define CallNPP_HandleEventProc(FUNC, NPParg, voidPtr) \ + (int16)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_HandleEventProcInfo, (NPParg), (voidPtr)) + +#else + +typedef int16 (* NP_LOADDS NPP_HandleEventUPP)(NPP instance, void* event); +#define NewNPP_HandleEventProc(FUNC) \ + ((NPP_HandleEventUPP) (FUNC)) +#define CallNPP_HandleEventProc(FUNC, NPParg, voidPtr) \ + (*(FUNC))((NPParg), (voidPtr)) + +#endif + + +/* NPP_URLNotify */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_URLNotifyUPP; +enum { + uppNPP_URLNotifyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*))) + | RESULT_SIZE(SIZE_CODE(SIZE_CODE(0))) +}; +#define NewNPP_URLNotifyProc(FUNC) \ + (NPP_URLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_URLNotifyProcInfo, GetCurrentArchitecture()) +#define CallNPP_URLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_URLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4)) + +#else + +typedef void (* NP_LOADDS NPP_URLNotifyUPP)(NPP instance, const char* url, NPReason reason, void* notifyData); +#define NewNPP_URLNotifyProc(FUNC) \ + ((NPP_URLNotifyUPP) (FUNC)) +#define CallNPP_URLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +#endif + + +/* NPP_GetValue */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_GetValueUPP; +enum { + uppNPP_GetValueProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPVariable))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_GetValueProc(FUNC) \ + (NPP_GetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_GetValueProcInfo, GetCurrentArchitecture()) +#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_GetValueProcInfo, (ARG1), (ARG2), (ARG3)) +#else + +typedef NPError (* NP_LOADDS NPP_GetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue); +#define NewNPP_GetValueProc(FUNC) \ + ((NPP_GetValueUPP) (FUNC)) +#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) +#endif + + +/* NPP_SetValue */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_SetValueUPP; +enum { + uppNPP_SetValueProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPNVariable))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_SetValueProc(FUNC) \ + (NPP_SetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_SetValueProcInfo, GetCurrentArchitecture()) +#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_SetValueProcInfo, (ARG1), (ARG2), (ARG3)) +#else + +typedef NPError (* NP_LOADDS NPP_SetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue); +#define NewNPP_SetValueProc(FUNC) \ + ((NPP_SetValueUPP) (FUNC)) +#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) +#endif + + +/* + * Netscape entry points + */ + + +/* NPN_GetValue */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetValueUPP; +enum { + uppNPN_GetValueProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPNVariable))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_GetValueProc(FUNC) \ + (NPN_GetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetValueProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetValueProcInfo, (ARG1), (ARG2), (ARG3)) +#else + +typedef NPError (* NP_LOADDS NPN_GetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue); +#define NewNPN_GetValueProc(FUNC) \ + ((NPN_GetValueUPP) (FUNC)) +#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) +#endif + + +/* NPN_SetValue */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_SetValueUPP; +enum { + uppNPN_SetValueProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPVariable))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_SetValueProc(FUNC) \ + (NPN_SetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetValueProcInfo, GetCurrentArchitecture()) +#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetValueProcInfo, (ARG1), (ARG2), (ARG3)) +#else + +typedef NPError (* NP_LOADDS NPN_SetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue); +#define NewNPN_SetValueProc(FUNC) \ + ((NPN_SetValueUPP) (FUNC)) +#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) +#endif + + +/* NPN_GetUrlNotify */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetURLNotifyUPP; +enum { + uppNPN_GetURLNotifyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_GetURLNotifyProc(FUNC) \ + (NPN_GetURLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetURLNotifyProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetURLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4)) +#else + +typedef NPError (* NP_LOADDS NPN_GetURLNotifyUPP)(NPP instance, const char* url, const char* window, void* notifyData); +#define NewNPN_GetURLNotifyProc(FUNC) \ + ((NPN_GetURLNotifyUPP) (FUNC)) +#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) +#endif + + +/* NPN_PostUrlNotify */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_PostURLNotifyUPP; +enum { + uppNPN_PostURLNotifyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(uint32))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPBool))) + | STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(void*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_PostURLNotifyProc(FUNC) \ + (NPN_PostURLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PostURLNotifyProcInfo, GetCurrentArchitecture()) +#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PostURLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) +#else + +typedef NPError (* NP_LOADDS NPN_PostURLNotifyUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); +#define NewNPN_PostURLNotifyProc(FUNC) \ + ((NPN_PostURLNotifyUPP) (FUNC)) +#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) +#endif + + +/* NPN_GetUrl */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetURLUPP; +enum { + uppNPN_GetURLProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_GetURLProc(FUNC) \ + (NPN_GetURLUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetURLProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetURLProcInfo, (ARG1), (ARG2), (ARG3)) +#else + +typedef NPError (* NP_LOADDS NPN_GetURLUPP)(NPP instance, const char* url, const char* window); +#define NewNPN_GetURLProc(FUNC) \ + ((NPN_GetURLUPP) (FUNC)) +#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) +#endif + + +/* NPN_PostUrl */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_PostURLUPP; +enum { + uppNPN_PostURLProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(uint32))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(const char*))) + | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPBool))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_PostURLProc(FUNC) \ + (NPN_PostURLUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PostURLProcInfo, GetCurrentArchitecture()) +#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PostURLProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) +#else + +typedef NPError (* NP_LOADDS NPN_PostURLUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file); +#define NewNPN_PostURLProc(FUNC) \ + ((NPN_PostURLUPP) (FUNC)) +#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) +#endif + + +/* NPN_RequestRead */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_RequestReadUPP; +enum { + uppNPN_RequestReadProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPByteRange *))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_RequestReadProc(FUNC) \ + (NPN_RequestReadUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RequestReadProcInfo, GetCurrentArchitecture()) +#define CallNPN_RequestReadProc(FUNC, stream, range) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RequestReadProcInfo, (stream), (range)) + +#else + +typedef NPError (* NP_LOADDS NPN_RequestReadUPP)(NPStream* stream, NPByteRange* rangeList); +#define NewNPN_RequestReadProc(FUNC) \ + ((NPN_RequestReadUPP) (FUNC)) +#define CallNPN_RequestReadProc(FUNC, stream, range) \ + (*(FUNC))((stream), (range)) + +#endif + + +/* NPN_NewStream */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_NewStreamUPP; +enum { + uppNPN_NewStreamProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPMIMEType))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char *))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPStream **))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_NewStreamProc(FUNC) \ + (NPN_NewStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_NewStreamProcInfo, GetCurrentArchitecture()) +#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_NewStreamProcInfo, (npp), (type), (window), (stream)) + +#else + +typedef NPError (* NP_LOADDS NPN_NewStreamUPP)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); +#define NewNPN_NewStreamProc(FUNC) \ + ((NPN_NewStreamUPP) (FUNC)) +#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream) \ + (*(FUNC))((npp), (type), (window), (stream)) + +#endif + + +/* NPN_Write */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_WriteUPP; +enum { + uppNPN_WriteProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int32))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*))) + | RESULT_SIZE(SIZE_CODE(sizeof(int32))) +}; +#define NewNPN_WriteProc(FUNC) \ + (NPN_WriteUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_WriteProcInfo, GetCurrentArchitecture()) +#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer) \ + (int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_WriteProcInfo, (npp), (stream), (len), (buffer)) + +#else + +typedef int32 (* NP_LOADDS NPN_WriteUPP)(NPP instance, NPStream* stream, int32 len, void* buffer); +#define NewNPN_WriteProc(FUNC) \ + ((NPN_WriteUPP) (FUNC)) +#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer) \ + (*(FUNC))((npp), (stream), (len), (buffer)) + +#endif + + +/* NPN_DestroyStream */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_DestroyStreamUPP; +enum { + uppNPN_DestroyStreamProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP ))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPN_DestroyStreamProc(FUNC) \ + (NPN_DestroyStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_DestroyStreamProcInfo, GetCurrentArchitecture()) +#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason) \ + (NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_DestroyStreamProcInfo, (npp), (stream), (reason)) + +#else + +typedef NPError (* NP_LOADDS NPN_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason); +#define NewNPN_DestroyStreamProc(FUNC) \ + ((NPN_DestroyStreamUPP) (FUNC)) +#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason) \ + (*(FUNC))((npp), (stream), (reason)) + +#endif + + +/* NPN_Status */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_StatusUPP; +enum { + uppNPN_StatusProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *))) +}; + +#define NewNPN_StatusProc(FUNC) \ + (NPN_StatusUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_StatusProcInfo, GetCurrentArchitecture()) +#define CallNPN_StatusProc(FUNC, npp, msg) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_StatusProcInfo, (npp), (msg)) + +#else + +typedef void (* NP_LOADDS NPN_StatusUPP)(NPP instance, const char* message); +#define NewNPN_StatusProc(FUNC) \ + ((NPN_StatusUPP) (FUNC)) +#define CallNPN_StatusProc(FUNC, npp, msg) \ + (*(FUNC))((npp), (msg)) + +#endif + + +/* NPN_UserAgent */ +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_UserAgentUPP; +enum { + uppNPN_UserAgentProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | RESULT_SIZE(SIZE_CODE(sizeof(const char *))) +}; + +#define NewNPN_UserAgentProc(FUNC) \ + (NPN_UserAgentUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_UserAgentProcInfo, GetCurrentArchitecture()) +#define CallNPN_UserAgentProc(FUNC, ARG1) \ + (const char*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_UserAgentProcInfo, (ARG1)) + +#else + +typedef const char* (* NP_LOADDS NPN_UserAgentUPP)(NPP instance); +#define NewNPN_UserAgentProc(FUNC) \ + ((NPN_UserAgentUPP) (FUNC)) +#define CallNPN_UserAgentProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + + +/* NPN_MemAlloc */ +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_MemAllocUPP; +enum { + uppNPN_MemAllocProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(uint32))) + | RESULT_SIZE(SIZE_CODE(sizeof(void *))) +}; + +#define NewNPN_MemAllocProc(FUNC) \ + (NPN_MemAllocUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemAllocProcInfo, GetCurrentArchitecture()) +#define CallNPN_MemAllocProc(FUNC, ARG1) \ + (void*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemAllocProcInfo, (ARG1)) + +#else + +typedef void* (* NP_LOADDS NPN_MemAllocUPP)(uint32 size); +#define NewNPN_MemAllocProc(FUNC) \ + ((NPN_MemAllocUPP) (FUNC)) +#define CallNPN_MemAllocProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + + +/* NPN__MemFree */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_MemFreeUPP; +enum { + uppNPN_MemFreeProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(void *))) +}; + +#define NewNPN_MemFreeProc(FUNC) \ + (NPN_MemFreeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemFreeProcInfo, GetCurrentArchitecture()) +#define CallNPN_MemFreeProc(FUNC, ARG1) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemFreeProcInfo, (ARG1)) + +#else + +typedef void (* NP_LOADDS NPN_MemFreeUPP)(void* ptr); +#define NewNPN_MemFreeProc(FUNC) \ + ((NPN_MemFreeUPP) (FUNC)) +#define CallNPN_MemFreeProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + + +/* NPN_MemFlush */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_MemFlushUPP; +enum { + uppNPN_MemFlushProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(uint32))) + | RESULT_SIZE(SIZE_CODE(sizeof(uint32))) +}; + +#define NewNPN_MemFlushProc(FUNC) \ + (NPN_MemFlushUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemFlushProcInfo, GetCurrentArchitecture()) +#define CallNPN_MemFlushProc(FUNC, ARG1) \ + (uint32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemFlushProcInfo, (ARG1)) + +#else + +typedef uint32 (* NP_LOADDS NPN_MemFlushUPP)(uint32 size); +#define NewNPN_MemFlushProc(FUNC) \ + ((NPN_MemFlushUPP) (FUNC)) +#define CallNPN_MemFlushProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + + + +/* NPN_ReloadPlugins */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_ReloadPluginsUPP; +enum { + uppNPN_ReloadPluginsProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPBool))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_ReloadPluginsProc(FUNC) \ + (NPN_ReloadPluginsUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReloadPluginsProcInfo, GetCurrentArchitecture()) +#define CallNPN_ReloadPluginsProc(FUNC, ARG1) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReloadPluginsProcInfo, (ARG1)) + +#else + +typedef void (* NP_LOADDS NPN_ReloadPluginsUPP)(NPBool reloadPages); +#define NewNPN_ReloadPluginsProc(FUNC) \ + ((NPN_ReloadPluginsUPP) (FUNC)) +#define CallNPN_ReloadPluginsProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_GetJavaEnv */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetJavaEnvUPP; +enum { + uppNPN_GetJavaEnvProcInfo = kThinkCStackBased + | RESULT_SIZE(SIZE_CODE(sizeof(JRIEnv*))) +}; + +#define NewNPN_GetJavaEnvProc(FUNC) \ + (NPN_GetJavaEnvUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetJavaEnvProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetJavaEnvProc(FUNC) \ + (JRIEnv*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetJavaEnvProcInfo) + +#else +typedef JRIEnv* (* NP_LOADDS NPN_GetJavaEnvUPP)(void); +#define NewNPN_GetJavaEnvProc(FUNC) \ + ((NPN_GetJavaEnvUPP) (FUNC)) +#define CallNPN_GetJavaEnvProc(FUNC) \ + (*(FUNC))() + +#endif + + +/* NPN_GetJavaPeer */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetJavaPeerUPP; +enum { + uppNPN_GetJavaPeerProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | RESULT_SIZE(SIZE_CODE(sizeof(jref))) +}; + +#define NewNPN_GetJavaPeerProc(FUNC) \ + (NPN_GetJavaPeerUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetJavaPeerProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetJavaPeerProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetJavaPeerProcInfo, (ARG1)) + +#else + +typedef jref (* NP_LOADDS NPN_GetJavaPeerUPP)(NPP instance); +#define NewNPN_GetJavaPeerProc(FUNC) \ + ((NPN_GetJavaPeerUPP) (FUNC)) +#define CallNPN_GetJavaPeerProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_InvalidateRect */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_InvalidateRectUPP; +enum { + uppNPN_InvalidateRectProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPRect *))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_InvalidateRectProc(FUNC) \ + (NPN_InvalidateRectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvalidateRectProcInfo, GetCurrentArchitecture()) +#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvalidateRectProcInfo, (ARG1), (ARG2)) + +#else + +typedef void (* NP_LOADDS NPN_InvalidateRectUPP)(NPP instance, NPRect *rect); +#define NewNPN_InvalidateRectProc(FUNC) \ + ((NPN_InvalidateRectUPP) (FUNC)) +#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + + +/* NPN_InvalidateRegion */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_InvalidateRegionUPP; +enum { + uppNPN_InvalidateRegionProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPRegion))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_InvalidateRegionProc(FUNC) \ + (NPN_InvalidateRegionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvalidateRegionProcInfo, GetCurrentArchitecture()) +#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2) \ + (void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvalidateRegionProcInfo, (ARG1), (ARG2)) + +#else + +typedef void (* NP_LOADDS NPN_InvalidateRegionUPP)(NPP instance, NPRegion region); +#define NewNPN_InvalidateRegionProc(FUNC) \ + ((NPN_InvalidateRegionUPP) (FUNC)) +#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + +/* NPN_ForceRedraw */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_ForceRedrawUPP; +enum { + uppNPN_ForceRedrawProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | RESULT_SIZE(SIZE_CODE(sizeof(0))) +}; + +#define NewNPN_ForceRedrawProc(FUNC) \ + (NPN_ForceRedrawUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ForceRedrawProcInfo, GetCurrentArchitecture()) +#define CallNPN_ForceRedrawProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ForceRedrawProcInfo, (ARG1)) + +#else + +typedef void (* NP_LOADDS NPN_ForceRedrawUPP)(NPP instance); +#define NewNPN_ForceRedrawProc(FUNC) \ + ((NPN_ForceRedrawUPP) (FUNC)) +#define CallNPN_ForceRedrawProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_GetStringIdentifier */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetStringIdentifierUPP; +enum { + uppNPN_GetStringIdentifierProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const NPUTF8*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPIdentifier))) +}; + +#define NewNPN_GetStringIdentifierProc(FUNC) \ + (NPN_GetStringIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetStringIdentifierProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetStringIdentifierProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetStringIdentifierProcInfo, (ARG1)) + +#else + +typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierUPP)(const NPUTF8* name); +#define NewNPN_GetStringIdentifierProc(FUNC) \ + ((NPN_GetStringIdentifierUPP) (FUNC)) +#define CallNPN_GetStringIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_GetStringIdentifiers */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetStringIdentifiersUPP; +enum { + uppNPN_GetStringIdentifiersProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const NPUTF8**))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(int32_t))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier*))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_GetStringIdentifiersProc(FUNC) \ + (NPN_GetStringIdentifiersUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetStringIdentifiersProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetStringIdentifiersProcInfo, (ARG1), (ARG2), (ARG3)) + +#else + +typedef void (* NP_LOADDS NPN_GetStringIdentifiersUPP)(const NPUTF8** names, + int32_t nameCount, + NPIdentifier* identifiers); +#define NewNPN_GetStringIdentifiersProc(FUNC) \ + ((NPN_GetStringIdentifiersUPP) (FUNC)) +#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +#endif + +/* NPN_GetIntIdentifier */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetIntIdentifierUPP; +enum { + uppNPN_GetIntIdentifierProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(int32_t))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPIdentifier))) +}; + +#define NewNPN_GetIntIdentifierProc(FUNC) \ + (NPN_GetIntIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetIntIdentifierProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetIntIdentifierProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetIntIdentifierProcInfo, (ARG1)) + +#else + +typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierUPP)(int32_t intid); +#define NewNPN_GetIntIdentifierProc(FUNC) \ + ((NPN_GetIntIdentifierUPP) (FUNC)) +#define CallNPN_GetIntIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_IdentifierIsString */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_IdentifierIsStringUPP; +enum { + uppNPN_IdentifierIsStringProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier identifier))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_IdentifierIsStringProc(FUNC) \ + (NPN_IdentifierIsStringUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_IdentifierIsStringProcInfo, GetCurrentArchitecture()) +#define CallNPN_IdentifierIsStringProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_IdentifierIsStringProcInfo, (ARG1)) + +#else + +typedef bool (* NP_LOADDS NPN_IdentifierIsStringUPP)(NPIdentifier identifier); +#define NewNPN_IdentifierIsStringProc(FUNC) \ + ((NPN_IdentifierIsStringUPP) (FUNC)) +#define CallNPN_IdentifierIsStringProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_UTF8FromIdentifier */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_UTF8FromIdentifierUPP; +enum { + uppNPN_UTF8FromIdentifierProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPUTF8*))) +}; + +#define NewNPN_UTF8FromIdentifierProc(FUNC) \ + (NPN_UTF8FromIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_UTF8FromIdentifierProcInfo, GetCurrentArchitecture()) +#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_UTF8FromIdentifierProcInfo, (ARG1)) + +#else + +typedef NPUTF8* (* NP_LOADDS NPN_UTF8FromIdentifierUPP)(NPIdentifier identifier); +#define NewNPN_UTF8FromIdentifierProc(FUNC) \ + ((NPN_UTF8FromIdentifierUPP) (FUNC)) +#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_IntFromIdentifier */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_IntFromIdentifierUPP; +enum { + uppNPN_IntFromIdentifierProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier))) + | RESULT_SIZE(SIZE_CODE(sizeof(int32_t))) +}; + +#define NewNPN_IntFromIdentifierProc(FUNC) \ + (NPN_IntFromIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_IntFromIdentifierProcInfo, GetCurrentArchitecture()) +#define CallNPN_IntFromIdentifierProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_IntFromIdentifierProcInfo, (ARG1)) + +#else + +typedef int32_t (* NP_LOADDS NPN_IntFromIdentifierUPP)(NPIdentifier identifier); +#define NewNPN_IntFromIdentifierProc(FUNC) \ + ((NPN_IntFromIdentifierUPP) (FUNC)) +#define CallNPN_IntFromIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_CreateObject */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_CreateObjectUPP; +enum { + uppNPN_CreateObjectProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPClass*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPObject*))) +}; + +#define NewNPN_CreateObjectProc(FUNC) \ + (NPN_CreateObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_CreateObjectProcInfo, GetCurrentArchitecture()) +#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_CreateObjectProcInfo, (ARG1), (ARG2)) + +#else + +typedef NPObject* (* NP_LOADDS NPN_CreateObjectUPP)(NPP npp, NPClass *aClass); +#define NewNPN_CreateObjectProc(FUNC) \ + ((NPN_CreateObjectUPP) (FUNC)) +#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + +/* NPN_RetainObject */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_RetainObjectUPP; +enum { + uppNPN_RetainObjectProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPObject*))) +}; + +#define NewNPN_RetainObjectProc(FUNC) \ + (NPN_RetainObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RetainObjectProcInfo, GetCurrentArchitecture()) +#define CallNPN_RetainObjectProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RetainObjectProcInfo, (ARG1)) + +#else + +typedef NPObject* (* NP_LOADDS NPN_RetainObjectUPP)(NPObject *obj); +#define NewNPN_RetainObjectProc(FUNC) \ + ((NPN_RetainObjectUPP) (FUNC)) +#define CallNPN_RetainObjectProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_ReleaseObject */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_ReleaseObjectUPP; +enum { + uppNPN_ReleaseObjectProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_ReleaseObjectProc(FUNC) \ + (NPN_ReleaseObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReleaseObjectProcInfo, GetCurrentArchitecture()) +#define CallNPN_ReleaseObjectProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReleaseObjectProcInfo, (ARG1)) + +#else + +typedef void (* NP_LOADDS NPN_ReleaseObjectUPP)(NPObject *obj); +#define NewNPN_ReleaseObjectProc(FUNC) \ + ((NPN_ReleaseObjectUPP) (FUNC)) +#define CallNPN_ReleaseObjectProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_Invoke */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_InvokeUPP; +enum { + uppNPN_InvokeProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint32_t))) + | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPVariant*))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_InvokeProc(FUNC) \ + (NPN_InvokeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvokeProcInfo, GetCurrentArchitecture()) +#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvokeProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) + +#else + +typedef bool (* NP_LOADDS NPN_InvokeUPP)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); +#define NewNPN_InvokeProc(FUNC) \ + ((NPN_InvokeUPP) (FUNC)) +#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) + +#endif + +/* NPN_InvokeDefault */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_InvokeDefaultUPP; +enum { + uppNPN_InvokeDefaultProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint32_t))) + | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPVariant*))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_InvokeDefaultProc(FUNC) \ + (NPN_InvokeDefaultUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvokeDefaultProcInfo, GetCurrentArchitecture()) +#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvokeDefaultProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) + +#else + +typedef bool (* NP_LOADDS NPN_InvokeDefaultUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +#define NewNPN_InvokeDefaultProc(FUNC) \ + ((NPN_InvokeDefaultUPP) (FUNC)) +#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) + +#endif + +/* NPN_Evaluate */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_EvaluateUPP; +enum { + uppNPN_EvaluateProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPString*))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPVariant*))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_EvaluateProc(FUNC) \ + (NPN_EvaluateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_EvaluateProcInfo, GetCurrentArchitecture()) +#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_EvaluateProcInfo, (ARG1), (ARG2), (ARG3), (ARG4)) + +#else + +typedef bool (* NP_LOADDS NPN_EvaluateUPP)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); +#define NewNPN_EvaluateProc(FUNC) \ + ((NPN_EvaluateUPP) (FUNC)) +#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +#endif + +/* NPN_GetProperty */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_GetPropertyUPP; +enum { + uppNPN_GetPropertyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPVariant*))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_GetPropertyProc(FUNC) \ + (NPN_GetPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetPropertyProcInfo, GetCurrentArchitecture()) +#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetPropertyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4)) + +#else + +typedef bool (* NP_LOADDS NPN_GetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); +#define NewNPN_GetPropertyProc(FUNC) \ + ((NPN_GetPropertyUPP) (FUNC)) +#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +#endif + +/* NPN_SetProperty */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_SetPropertyUPP; +enum { + uppNPN_SetPropertyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_SetPropertyProc(FUNC) \ + (NPN_SetPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetPropertyProcInfo, GetCurrentArchitecture()) +#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetPropertyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4)) + +#else + +typedef bool (* NP_LOADDS NPN_SetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); +#define NewNPN_SetPropertyProc(FUNC) \ + ((NPN_SetPropertyUPP) (FUNC)) +#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +#endif + +/* NPN_RemoveProperty */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_RemovePropertyUPP; +enum { + uppNPN_RemovePropertyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_RemovePropertyProc(FUNC) \ + (NPN_RemovePropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RemovePropertyProcInfo, GetCurrentArchitecture()) +#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RemovePropertyProcInfo, (ARG1), (ARG2), (ARG3)) + +#else + +typedef bool (* NP_LOADDS NPN_RemovePropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +#define NewNPN_RemovePropertyProc(FUNC) \ + ((NPN_RemovePropertyUPP) (FUNC)) +#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +#endif + +/* NPN_HasProperty */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_HasPropertyUPP; +enum { + uppNPN_HasPropertyProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_HasPropertyProc(FUNC) \ + (NPN_HasPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_HasPropertyProcInfo, GetCurrentArchitecture()) +#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_HasPropertyProcInfo, (ARG1), (ARG2), (ARG3)) + +#else + +typedef bool (* NP_LOADDS NPN_HasPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +#define NewNPN_HasPropertyProc(FUNC) \ + ((NPN_HasPropertyUPP) (FUNC)) +#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +#endif + +/* NPN_HasMethod */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_HasMethodUPP; +enum { + uppNPN_HasMethodProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier))) + | RESULT_SIZE(SIZE_CODE(sizeof(bool))) +}; + +#define NewNPN_HasMethodProc(FUNC) \ + (NPN_HasMethodUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_HasMethodProcInfo, GetCurrentArchitecture()) +#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_HasMethodProcInfo, (ARG1), (ARG2), (ARG3)) + +#else + +typedef bool (* NP_LOADDS NPN_HasMethodUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +#define NewNPN_HasMethodProc(FUNC) \ + ((NPN_HasMethodUPP) (FUNC)) +#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +#endif + +/* NPN_ReleaseVariantValue */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_ReleaseVariantValue; +enum { + uppNPN_ReleaseVariantValueProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPVariant*))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_ReleaseVariantValueProc(FUNC) \ + (NPN_ReleaseVariantValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReleaseVariantValueProcInfo, GetCurrentArchitecture()) +#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReleaseVariantValueProcInfo, (ARG1)) + +#else + +typedef void (* NP_LOADDS NPN_ReleaseVariantValueUPP)(NPVariant *variant); +#define NewNPN_ReleaseVariantValueProc(FUNC) \ + ((NPN_ReleaseVariantValueUPP) (FUNC)) +#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + +/* NPN_SetException */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_SetExceptionUPP; +enum { + uppNPN_SetExceptionProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const NPUTF8*))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_SetExceptionProc(FUNC) \ + (NPN_SetExceptionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetExceptionProcInfo, GetCurrentArchitecture()) +#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetExceptionProcInfo, (ARG1), (ARG2)) + +#else + +typedef void (* NP_LOADDS NPN_SetExceptionUPP)(NPObject *obj, const NPUTF8 *message); +#define NewNPN_SetExceptionProc(FUNC) \ + ((NPN_SetExceptionUPP) (FUNC)) +#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + +/* NPN_PushPopupsEnabledStateUPP */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_PushPopupsEnabledStateUPP; +enum { + uppNPN_PushPopupsEnabledStateProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPBool))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_PushPopupsEnabledStateProc(FUNC) \ + (NPN_PushPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, GetCurrentArchitecture()) +#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, (ARG1), (ARG2)) + +#else + +typedef bool (* NP_LOADDS NPN_PushPopupsEnabledStateUPP)(NPP npp, NPBool enabled); +#define NewNPN_PushPopupsEnabledStateProc(FUNC) \ + ((NPN_PushPopupsEnabledStateUPP) (FUNC)) +#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +#endif + +/* NPN_PopPopupsEnabledState */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPN_PopPopupsEnabledStateUPP; +enum { + uppNPN_PopPopupsEnabledStateProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP))) + | RESULT_SIZE(SIZE_CODE(0)) +}; + +#define NewNPN_PopPopupsEnabledStateProc(FUNC) \ + (NPN_PopPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, GetCurrentArchitecture()) +#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1) \ + (jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, (ARG1)) + +#else + +typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp); +#define NewNPN_PopPopupsEnabledStateProc(FUNC) \ + ((NPN_PopPopupsEnabledStateUPP) (FUNC)) +#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +#endif + + + +/****************************************************************************************** + * The actual plugin function table definitions + *******************************************************************************************/ + +#ifdef XP_MAC +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#endif +#endif + +typedef struct _NPPluginFuncs { + uint16 size; + uint16 version; + NPP_NewUPP newp; + NPP_DestroyUPP destroy; + NPP_SetWindowUPP setwindow; + NPP_NewStreamUPP newstream; + NPP_DestroyStreamUPP destroystream; + NPP_StreamAsFileUPP asfile; + NPP_WriteReadyUPP writeready; + NPP_WriteUPP write; + NPP_PrintUPP print; + NPP_HandleEventUPP event; + NPP_URLNotifyUPP urlnotify; + JRIGlobalRef javaClass; + NPP_GetValueUPP getvalue; + NPP_SetValueUPP setvalue; +} NPPluginFuncs; + +typedef struct _NPNetscapeFuncs { + uint16 size; + uint16 version; + NPN_GetURLUPP geturl; + NPN_PostURLUPP posturl; + NPN_RequestReadUPP requestread; + NPN_NewStreamUPP newstream; + NPN_WriteUPP write; + NPN_DestroyStreamUPP destroystream; + NPN_StatusUPP status; + NPN_UserAgentUPP uagent; + NPN_MemAllocUPP memalloc; + NPN_MemFreeUPP memfree; + NPN_MemFlushUPP memflush; + NPN_ReloadPluginsUPP reloadplugins; + NPN_GetJavaEnvUPP getJavaEnv; + NPN_GetJavaPeerUPP getJavaPeer; + NPN_GetURLNotifyUPP geturlnotify; + NPN_PostURLNotifyUPP posturlnotify; + NPN_GetValueUPP getvalue; + NPN_SetValueUPP setvalue; + NPN_InvalidateRectUPP invalidaterect; + NPN_InvalidateRegionUPP invalidateregion; + NPN_ForceRedrawUPP forceredraw; + NPN_GetStringIdentifierUPP getstringidentifier; + NPN_GetStringIdentifiersUPP getstringidentifiers; + NPN_GetIntIdentifierUPP getintidentifier; + NPN_IdentifierIsStringUPP identifierisstring; + NPN_UTF8FromIdentifierUPP utf8fromidentifier; + NPN_IntFromIdentifierUPP intfromidentifier; + NPN_CreateObjectUPP createobject; + NPN_RetainObjectUPP retainobject; + NPN_ReleaseObjectUPP releaseobject; + NPN_InvokeUPP invoke; + NPN_InvokeDefaultUPP invokeDefault; + NPN_EvaluateUPP evaluate; + NPN_GetPropertyUPP getproperty; + NPN_SetPropertyUPP setproperty; + NPN_RemovePropertyUPP removeproperty; + NPN_HasPropertyUPP hasproperty; + NPN_HasMethodUPP hasmethod; + NPN_ReleaseVariantValueUPP releasevariantvalue; + NPN_SetExceptionUPP setexception; + NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate; + NPN_PopPopupsEnabledStateUPP poppopupsenabledstate; +} NPNetscapeFuncs; + +#ifdef XP_MAC +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#endif +#endif + + +#if defined(XP_MAC) || defined(XP_MACOSX) +/****************************************************************************************** + * Mac platform-specific plugin glue stuff + *******************************************************************************************/ + +/* + * Main entry point of the plugin. + * This routine will be called when the plugin is loaded. The function + * tables are passed in and the plugin fills in the NPPluginFuncs table + * and NPPShutdownUPP for Netscape's use. + */ + +#if _NPUPP_USE_UPP_ + +typedef UniversalProcPtr NPP_MainEntryUPP; +enum { + uppNPP_MainEntryProcInfo = kThinkCStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPNetscapeFuncs*))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPluginFuncs*))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPP_ShutdownUPP*))) + | RESULT_SIZE(SIZE_CODE(sizeof(NPError))) +}; +#define NewNPP_MainEntryProc(FUNC) \ + (NPP_MainEntryUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_MainEntryProcInfo, GetCurrentArchitecture()) +#define CallNPP_MainEntryProc(FUNC, netscapeFunc, pluginFunc, shutdownUPP) \ + CallUniversalProc((UniversalProcPtr)(FUNC), (ProcInfoType)uppNPP_MainEntryProcInfo, (netscapeFunc), (pluginFunc), (shutdownUPP)) + +#else + +typedef NPError (* NP_LOADDS NPP_MainEntryUPP)(NPNetscapeFuncs*, NPPluginFuncs*, NPP_ShutdownUPP*); +#define NewNPP_MainEntryProc(FUNC) \ + ((NPP_MainEntryUPP) (FUNC)) +#define CallNPP_MainEntryProc(FUNC, netscapeFunc, pluginFunc, shutdownUPP) \ + (*(FUNC))((netscapeFunc), (pluginFunc), (shutdownUPP)) + +#endif + + +/* + * Mac version(s) of NP_GetMIMEDescription(const char *) + * These can be called to retreive MIME information from the plugin dynamically + * + * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way + * to get mime info from the plugin only on OSX and may not be supported + * in furture version--use NP_GetMIMEDescription instead + */ + +enum +{ + kBPSupportedMIMETypesStructVers_1 = 1 +}; + +typedef struct _BPSupportedMIMETypes +{ + SInt32 structVersion; /* struct version */ + Handle typeStrings; /* STR# formated handle, allocated by plug-in */ + Handle infoStrings; /* STR# formated handle, allocated by plug-in */ +} BPSupportedMIMETypes; +OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags); + +#if _NPUPP_USE_UPP_ + +#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescriptionRD" +typedef UniversalProcPtr NP_GetMIMEDescriptionUPP; +enum { + uppNP_GetMIMEDescEntryProc = kThinkCStackBased + | RESULT_SIZE(SIZE_CODE(sizeof(const char *))) +}; +#define NewNP_GetMIMEDescEntryProc(FUNC) \ + (NP_GetMIMEDescriptionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNP_GetMIMEDescEntryProc, GetCurrentArchitecture()) +#define CallNP_GetMIMEDescEntryProc(FUNC) \ + (const char *)CallUniversalProc((UniversalProcPtr)(FUNC), (ProcInfoType)uppNP_GetMIMEDescEntryProc) + + +#else /* !_NPUPP_USE_UPP_ */ + + /* NP_GetMIMEDescription */ +#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription" +typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)(); +#define NewNP_GetMIMEDescEntryProc(FUNC) \ + ((NP_GetMIMEDescriptionUPP) (FUNC)) +#define CallNP_GetMIMEDescEntryProc(FUNC) \ + (*(FUNC))() +/* BP_GetSupportedMIMETypes */ +typedef OSErr (* NP_LOADDS BP_GetSupportedMIMETypesUPP)(BPSupportedMIMETypes*, UInt32); +#define NewBP_GetSupportedMIMETypesEntryProc(FUNC) \ + ((BP_GetSupportedMIMETypesUPP) (FUNC)) +#define CallBP_GetMIMEDescEntryProc(FUNC, mimeInfo, flags) \ + (*(FUNC))((mimeInfo), (flags)) + +#endif +#endif /* MAC */ + +#if defined(_WINDOWS) +#define OSCALL WINAPI +#else +#if defined(__OS2__) +#define OSCALL _System +#else +#define OSCALL +#endif +#endif + +#if defined( _WINDOWS ) || defined (__OS2__) + +#ifdef __cplusplus +extern "C" { +#endif + +/* plugin meta member functions */ +#if defined(__OS2__) + +typedef struct _NPPluginData { /* Alternate OS2 Plugin interface */ + char *pMimeTypes; + char *pFileExtents; + char *pFileOpenTemplate; + char *pProductName; + char *pProductDescription; + unsigned long dwProductVersionMS; + unsigned long dwProductVersionLS; +} NPPluginData; + +NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData); + +#endif + +NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs); + +NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs); + +NPError OSCALL NP_Shutdown(); + +char* NP_GetMIMEDescription(); + +#ifdef __cplusplus +} +#endif + +#endif /* _WINDOWS || __OS2__ */ + +#if defined(__OS2__) +#pragma pack() +#endif + +#ifdef XP_UNIX + +#ifdef __cplusplus +extern "C" { +#endif + +/* plugin meta member functions */ + +char* NP_GetMIMEDescription(void); +NPError NP_Initialize(NPNetscapeFuncs*, NPPluginFuncs*); +NPError NP_Shutdown(void); +NPError NP_GetValue(void *future, NPPVariable aVariable, void *aValue); + +#ifdef __cplusplus +} +#endif + +#endif /* XP_UNIX */ + +#endif /* _NPUPP_H_ */ diff --git a/src/moz-sdk/obsolete/protypes.h b/src/moz-sdk/obsolete/protypes.h new file mode 100644 index 0000000..4405bfc --- /dev/null +++ b/src/moz-sdk/obsolete/protypes.h @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This header typedefs the old 'native' types to the new PR<type>s. + * These definitions are scheduled to be eliminated at the earliest + * possible time. The NSPR API is implemented and documented using + * the new definitions. + */ + +#if !defined(PROTYPES_H) +#define PROTYPES_H + +typedef PRUintn uintn; +#ifndef _XP_Core_ +typedef PRIntn intn; +#endif + +/* + * It is trickier to define uint, int8, uint8, int16, uint16, + * int32, uint32, int64, and uint64 because some of these int + * types are defined by standard header files on some platforms. + * Our strategy here is to include all such standard headers + * first, and then define these int types only if they are not + * defined by those standard headers. + */ + +/* + * BeOS defines all the int types below in its standard header + * file SupportDefs.h. + */ +#ifdef XP_BEOS +#include <support/SupportDefs.h> +#endif + +/* + * OpenVMS defines all the int types below in its standard + * header files ints.h and types.h. + */ +#ifdef VMS +#include <ints.h> +#include <types.h> +#endif + +/* + * SVR4 typedef of uint is commonly found on UNIX machines. + * + * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h) + * defines the types int8, int16, int32, and int64. + */ +#ifdef XP_UNIX +#include <sys/types.h> +#endif + +/* model.h on HP-UX defines int8, int16, and int32. */ +#ifdef HPUX +#include <model.h> +#endif + +/* + * uint + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(XP_UNIX) || defined(NTO) +typedef PRUintn uint; +#endif + +/* + * uint64 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint64 uint64; +#endif + +/* + * uint32 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) +typedef PRUint32 uint32; +#else +typedef unsigned long uint32; +#endif +#endif + +/* + * uint16 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint16 uint16; +#endif + +/* + * uint8 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint8 uint8; +#endif + +/* + * int64 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) +typedef PRInt64 int64; +#endif + +/* + * int32 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) +typedef PRInt32 int32; +#else +typedef long int32; +#endif +#endif + +/* + * int16 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +typedef PRInt16 int16; +#endif + +/* + * int8 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +typedef PRInt8 int8; +#endif + +typedef PRFloat64 float64; +typedef PRUptrdiff uptrdiff_t; +typedef PRUword uprword_t; +typedef PRWord prword_t; + + +/* Re: prbit.h */ +#define TEST_BIT PR_TEST_BIT +#define SET_BIT PR_SET_BIT +#define CLEAR_BIT PR_CLEAR_BIT + +/* Re: prarena.h->plarena.h */ +#define PRArena PLArena +#define PRArenaPool PLArenaPool +#define PRArenaStats PLArenaStats +#define PR_ARENA_ALIGN PL_ARENA_ALIGN +#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL +#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE +#define PR_ARENA_GROW PL_ARENA_GROW +#define PR_ARENA_MARK PL_ARENA_MARK +#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED +#define PR_CLEAR_ARENA PL_CLEAR_ARENA +#define PR_ARENA_RELEASE PL_ARENA_RELEASE +#define PR_COUNT_ARENA PL_COUNT_ARENA +#define PR_ARENA_DESTROY PL_ARENA_DESTROY +#define PR_InitArenaPool PL_InitArenaPool +#define PR_FreeArenaPool PL_FreeArenaPool +#define PR_FinishArenaPool PL_FinishArenaPool +#define PR_CompactArenaPool PL_CompactArenaPool +#define PR_ArenaFinish PL_ArenaFinish +#define PR_ArenaAllocate PL_ArenaAllocate +#define PR_ArenaGrow PL_ArenaGrow +#define PR_ArenaRelease PL_ArenaRelease +#define PR_ArenaCountAllocation PL_ArenaCountAllocation +#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth +#define PR_ArenaCountGrowth PL_ArenaCountGrowth +#define PR_ArenaCountRelease PL_ArenaCountRelease +#define PR_ArenaCountRetract PL_ArenaCountRetract + +/* Re: prhash.h->plhash.h */ +#define PRHashEntry PLHashEntry +#define PRHashTable PLHashTable +#define PRHashNumber PLHashNumber +#define PRHashFunction PLHashFunction +#define PRHashComparator PLHashComparator +#define PRHashEnumerator PLHashEnumerator +#define PRHashAllocOps PLHashAllocOps +#define PR_NewHashTable PL_NewHashTable +#define PR_HashTableDestroy PL_HashTableDestroy +#define PR_HashTableRawLookup PL_HashTableRawLookup +#define PR_HashTableRawAdd PL_HashTableRawAdd +#define PR_HashTableRawRemove PL_HashTableRawRemove +#define PR_HashTableAdd PL_HashTableAdd +#define PR_HashTableRemove PL_HashTableRemove +#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries +#define PR_HashTableLookup PL_HashTableLookup +#define PR_HashTableDump PL_HashTableDump +#define PR_HashString PL_HashString +#define PR_CompareStrings PL_CompareStrings +#define PR_CompareValues PL_CompareValues + +#if defined(XP_MAC) +#ifndef TRUE /* Mac standard is lower case true */ + #define TRUE 1 +#endif +#ifndef FALSE /* Mac standard is lower case false */ + #define FALSE 0 +#endif +#endif + +#endif /* !defined(PROTYPES_H) */ diff --git a/src/moz-sdk/prcpucfg.h b/src/moz-sdk/prcpucfg.h new file mode 100644 index 0000000..7c5472f --- /dev/null +++ b/src/moz-sdk/prcpucfg.h @@ -0,0 +1,716 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file is used by not only Linux but also other glibc systems + * such as GNU/Hurd and GNU/k*BSD. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#if !defined(LINUX) && defined(__linux__) +#define LINUX +#endif + +#ifdef __FreeBSD_kernel__ +#define PR_AF_INET6 28 /* same as AF_INET6 */ +#else +#define PR_AF_INET6 10 /* same as AF_INET6 */ +#endif + +#ifdef __powerpc64__ + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__alpha) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__x86_64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mc68000__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 +#define PR_ALIGN_OF_WORD 2 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +#ifdef __MIPSEB__ +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown MIPS endianness." +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__arm__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__hppa__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390x__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#define HAVE_LONG_LONG +#if PR_ALIGN_OF_DOUBLE == 8 +#define HAVE_ALIGNED_DOUBLES +#endif +#if PR_ALIGN_OF_INT64 == 8 +#define HAVE_ALIGNED_LONGLONGS +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/src/moz-sdk/prtypes.h b/src/moz-sdk/prtypes.h new file mode 100644 index 0000000..09fe032 --- /dev/null +++ b/src/moz-sdk/prtypes.h @@ -0,0 +1,544 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: prtypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies that we have found +** in ANSI environments. +** +** Since we do not wrap <stdlib.h> and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef prtypes_h___ +#define prtypes_h___ + +#ifdef MDCPUCFG +#include MDCPUCFG +#else +#include "prcpucfg.h" +#endif + +#include <stddef.h> + +/*********************************************************************** +** MACROS: PR_EXTERN +** PR_IMPLEMENT +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** PR_EXTERN when the prototype for the method is declared. Use +** PR_IMPLEMENT for the implementation of the method. +** +** Example: +** in dowhim.h +** PR_EXTERN( void ) DoWhatIMean( void ); +** in dowhim.c +** PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(WIN16) + +#define PR_CALLBACK_DECL __cdecl + +#if defined(_WINDLL) +#define PR_EXPORT(__type) extern __type _cdecl _export _loadds +#define PR_IMPORT(__type) extern __type _cdecl _export _loadds +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export _loadds +#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* this must be .EXE */ +#define PR_EXPORT(__type) extern __type _cdecl _export +#define PR_IMPORT(__type) extern __type _cdecl _export +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export +#define PR_IMPLEMENT(__type) __type _cdecl _export +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK +#endif /* _WINDLL */ + +#elif defined(XP_MAC) + +#define PR_EXPORT(__type) extern __declspec(export) __type +#define PR_EXPORT_DATA(__type) extern __declspec(export) __type +#define PR_IMPORT(__type) extern __declspec(export) __type +#define PR_IMPORT_DATA(__type) extern __declspec(export) __type + +#define PR_EXTERN(__type) extern __declspec(export) __type +#define PR_IMPLEMENT(__type) __declspec(export) __type +#define PR_EXTERN_DATA(__type) extern __declspec(export) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2_VACPP) + +#define PR_EXPORT(__type) extern __type +#define PR_EXPORT_DATA(__type) extern __type +#define PR_IMPORT(__type) extern __type +#define PR_IMPORT_DATA(__type) extern __type + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type +#define PR_CALLBACK _Optlink +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* Unix */ + +/* GCC 3.3 and later support the visibility attribute. */ +#if (__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default"))) +#else +#define PR_VISIBILITY_DEFAULT +#endif + +#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type + +#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type +#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +/*********************************************************************** +** MACROS: PR_BEGIN_MACRO +** PR_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define PR_BEGIN_MACRO do { +#define PR_END_MACRO } while (0) + +/*********************************************************************** +** MACROS: PR_BEGIN_EXTERN_C +** PR_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus +#define PR_BEGIN_EXTERN_C extern "C" { +#define PR_END_EXTERN_C } +#else +#define PR_BEGIN_EXTERN_C +#define PR_END_EXTERN_C +#endif + +/*********************************************************************** +** MACROS: PR_BIT +** PR_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define PR_BIT(n) ((PRUint32)1 << (n)) +#define PR_BITMASK(n) (PR_BIT(n) - 1) + +/*********************************************************************** +** MACROS: PR_ROUNDUP +** PR_MIN +** PR_MAX +** PR_ABS +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define PR_MIN(x,y) ((x)<(y)?(x):(y)) +#define PR_MAX(x,y) ((x)>(y)?(x):(y)) +#define PR_ABS(x) ((x)<0?-(x):(x)) + +PR_BEGIN_EXTERN_C + +/************************************************************************ +** TYPES: PRUint8 +** PRInt8 +** DESCRIPTION: +** The int8 types are known to be 8 bits each. There is no type that +** is equivalent to a plain "char". +************************************************************************/ +#if PR_BYTES_PER_BYTE == 1 +typedef unsigned char PRUint8; +/* +** Some cfront-based C++ compilers do not like 'signed char' and +** issue the warning message: +** warning: "signed" not implemented (ignored) +** For these compilers, we have to define PRInt8 as plain 'char'. +** Make sure that plain 'char' is indeed signed under these compilers. +*/ +#if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif +#else +#error No suitable type for PRInt8/PRUint8 +#endif + +/************************************************************************ + * MACROS: PR_INT8_MAX + * PR_INT8_MIN + * PR_UINT8_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt8 or PRUint8. +************************************************************************/ + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +/************************************************************************ +** TYPES: PRUint16 +** PRInt16 +** DESCRIPTION: +** The int16 types are known to be 16 bits each. +************************************************************************/ +#if PR_BYTES_PER_SHORT == 2 +typedef unsigned short PRUint16; +typedef short PRInt16; +#else +#error No suitable type for PRInt16/PRUint16 +#endif + +/************************************************************************ + * MACROS: PR_INT16_MAX + * PR_INT16_MIN + * PR_UINT16_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt16 or PRUint16. +************************************************************************/ + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +/************************************************************************ +** TYPES: PRUint32 +** PRInt32 +** DESCRIPTION: +** The int32 types are known to be 32 bits each. +************************************************************************/ +#if PR_BYTES_PER_INT == 4 +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U +#elif PR_BYTES_PER_LONG == 4 +typedef unsigned long PRUint32; +typedef long PRInt32; +#define PR_INT32(x) x ## L +#define PR_UINT32(x) x ## UL +#else +#error No suitable type for PRInt32/PRUint32 +#endif + +/************************************************************************ + * MACROS: PR_INT32_MAX + * PR_INT32_MIN + * PR_UINT32_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt32 or PRUint32. +************************************************************************/ + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +/************************************************************************ +** TYPES: PRUint64 +** PRInt64 +** DESCRIPTION: +** The int64 types are known to be 64 bits each. Care must be used when +** declaring variables of type PRUint64 or PRInt64. Different hardware +** architectures and even different compilers have varying support for +** 64 bit values. The only guaranteed portability requires the use of +** the LL_ macros (see prlong.h). +************************************************************************/ +#ifdef HAVE_LONG_LONG +#if PR_BYTES_PER_LONG == 8 +typedef long PRInt64; +typedef unsigned long PRUint64; +#elif defined(WIN16) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#elif defined(WIN32) && !defined(__GNUC__) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#else +typedef long long PRInt64; +typedef unsigned long long PRUint64; +#endif /* PR_BYTES_PER_LONG == 8 */ +#else /* !HAVE_LONG_LONG */ +typedef struct { +#ifdef IS_LITTLE_ENDIAN + PRUint32 lo, hi; +#else + PRUint32 hi, lo; +#endif +} PRInt64; +typedef PRInt64 PRUint64; +#endif /* !HAVE_LONG_LONG */ + +/************************************************************************ +** TYPES: PRUintn +** PRIntn +** DESCRIPTION: +** The PRIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ +#if PR_BYTES_PER_INT >= 2 +typedef int PRIntn; +typedef unsigned int PRUintn; +#else +#error 'sizeof(int)' not sufficient for platform use +#endif + +/************************************************************************ +** TYPES: PRFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double PRFloat64; + +/************************************************************************ +** TYPES: PRSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t PRSize; + + +/************************************************************************ +** TYPES: PROffset32, PROffset64 +** DESCRIPTION: +** A type for representing byte offsets from some location. +************************************************************************/ +typedef PRInt32 PROffset32; +typedef PRInt64 PROffset64; + +/************************************************************************ +** TYPES: PRPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer subtraction. +************************************************************************/ +typedef ptrdiff_t PRPtrdiff; + +/************************************************************************ +** TYPES: PRUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +typedef unsigned long PRUptrdiff; + +/************************************************************************ +** TYPES: PRBool +** DESCRIPTION: +** Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** just as you would C int-valued conditions. +************************************************************************/ +typedef PRIntn PRBool; +#define PR_TRUE 1 +#define PR_FALSE 0 + +/************************************************************************ +** TYPES: PRPackedBool +** DESCRIPTION: +** Use PRPackedBool within structs where bitfields are not desirable +** but minimum and consistant overhead matters. +************************************************************************/ +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +#endif + +/* +** WARNING: The undocumented data types PRWord and PRUword are +** only used in the garbage collection and arena code. Do not +** use PRWord and PRUword in new code. +** +** A PRWord is an integer that is the same size as a void*. +** It implements the notion of a "word" in the Java Virtual +** Machine. (See Sec. 3.4 "Words", The Java Virtual Machine +** Specification, Addison-Wesley, September 1996. +** http://java.sun.com/docs/books/vmspec/index.html.) +*/ +typedef long PRWord; +typedef unsigned long PRUword; + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions until pr=>ds transition is done ***/ +/********************** Also, we are still using NSPR 1.0. GC ******************/ +/* +** Fundamental NSPR macros, used nearly everywhere. +*/ + +#define PR_PUBLIC_API PR_IMPLEMENT + +/* +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +*/ +#define NSPR_BEGIN_MACRO do { +#define NSPR_END_MACRO } while (0) + +/* +** Macro shorthands for conditional C++ extern block delimiters. +*/ +#ifdef NSPR_BEGIN_EXTERN_C +#undef NSPR_BEGIN_EXTERN_C +#endif +#ifdef NSPR_END_EXTERN_C +#undef NSPR_END_EXTERN_C +#endif + +#ifdef __cplusplus +#define NSPR_BEGIN_EXTERN_C extern "C" { +#define NSPR_END_EXTERN_C } +#else +#define NSPR_BEGIN_EXTERN_C +#define NSPR_END_EXTERN_C +#endif + +#ifdef XP_MAC +#include "protypes.h" +#else +#include "obsolete/protypes.h" +#endif + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* prtypes_h___ */ + diff --git a/src/noise.gif b/src/noise.gif Binary files differnew file mode 100644 index 0000000..55bf6ae --- /dev/null +++ b/src/noise.gif diff --git a/src/npplayer.c b/src/npplayer.c new file mode 100644 index 0000000..e7f67bb --- /dev/null +++ b/src/npplayer.c @@ -0,0 +1,1545 @@ +/* +* Copyright (C) 2007 Koos Vriezen <[email protected]> +* +* 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 +*/ + +/* gcc -o knpplayer `pkg-config --libs --cflags gtk+-x11-2.0` `pkg-config --libs --cflags dbus-glib-1` `pkg-config --libs gthread-2.0` npplayer.c + +http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ +http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html +*/ + +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/time.h> +#include <fcntl.h> + +#include <glib/gprintf.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> +#include <dbus/dbus-glib.h> + +#define XP_UNIX +#define MOZ_X11 +#include "moz-sdk/npupp.h" + +typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)(); +typedef NPError (* NP_GetValueUPP)(void *inst, NPPVariable var, void *value); +typedef NPError (* NP_InitializeUPP)(NPNetscapeFuncs*, NPPluginFuncs*); +typedef NPError (* NP_ShutdownUPP)(void); + +static gchar *plugin; +static gchar *object_url; +static gchar *mimetype; + +static DBusConnection *dbus_connection; +static char *service_name; +static gchar *callback_service; +static gchar *callback_path; +static GModule *library; +static GtkWidget *xembed; +static Window socket_id; +static Window parent_id; +static int top_w, top_h; +static int update_dimension_timer; +static int stdin_read_watch; + +static NPPluginFuncs np_funcs; /* plugin functions */ +static NPP npp; /* single instance of the plugin */ +static NPWindow np_window; +static NPObject *js_window; +static NPObject *scriptable_peer; +static NPSavedData *saved_data; +static NPClass js_class; +static GTree *stream_list; +static gpointer current_stream_id; +static uint32_t stream_chunk_size; +static char stream_buf[32 * 1024]; +static unsigned int stream_buf_pos; +static int stream_id_counter; +static GTree *identifiers; +static int js_obj_counter; +typedef struct _StreamInfo { + NPStream np_stream; + /*unsigned int stream_buf_pos;*/ + unsigned int stream_pos; + unsigned int total; + unsigned int reason; + char *url; + char *mimetype; + char *target; + bool notify; + bool called_plugin; + bool destroyed; +} StreamInfo; +struct JsObject; +typedef struct _JsObject { + NPObject npobject; + struct _JsObject * parent; + char * name; +} JsObject; + +static NP_GetMIMEDescriptionUPP npGetMIMEDescription; +static NP_GetValueUPP npGetValue; +static NP_InitializeUPP npInitialize; +static NP_ShutdownUPP npShutdown; + +static void callFunction(int stream, const char *func, int first_arg_type, ...); +static void readStdin (gpointer d, gint src, GdkInputCondition cond); +static char * evaluate (const char *script); + +/*----------------%<---------------------------------------------------------*/ + +static void print (const char * format, ...) { + va_list vl; + va_start (vl, format); + vprintf (format, vl); + va_end (vl); + fflush (stdout); +} + +/*----------------%<---------------------------------------------------------*/ + +static gint streamCompare (gconstpointer a, gconstpointer b) { + return (long)a - (long)b; +} + +static void freeStream (StreamInfo *si) { + if (!g_tree_remove (stream_list, si->np_stream.ndata)) + print ("WARNING freeStream not in tree\n"); + g_free (si->url); + if (si->mimetype) + g_free (si->mimetype); + if (si->target) + g_free (si->target); + free (si); +} + +static gboolean requestStream (void * p) { + StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); + if (si) { + if (!callback_service) + current_stream_id = p; + if (!stdin_read_watch) + stdin_read_watch = gdk_input_add (0, GDK_INPUT_READ,readStdin,NULL); + if (si->target) + callFunction ((int)(long)p, "getUrl", + DBUS_TYPE_STRING, &si->url, + DBUS_TYPE_STRING, &si->target, DBUS_TYPE_INVALID); + else + callFunction ((int)(long)p, "getUrl", + DBUS_TYPE_STRING, &si->url, DBUS_TYPE_INVALID); + } else { + print ("requestStream %d not found", (long) p); + } + return 0; /* single shot */ +} + +static gboolean destroyStream (void * p) { + StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); + print ("FIXME destroyStream\n"); + if (si) + callFunction ((int)(long)p, "destroy", DBUS_TYPE_INVALID); + return 0; /* single shot */ +} + +static void removeStream (void * p) { + StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); + + if (si) { + print ("removeStream %d rec:%d reason %d\n", (long) p, si->stream_pos, si->reason); + if (!si->destroyed) { + if (si->called_plugin && !si->target) { + si->np_stream.end = si->total; + np_funcs.destroystream (npp, &si->np_stream, si->reason); + } + if (si->notify) + np_funcs.urlnotify (npp, + si->url, si->reason, si->np_stream.notifyData); + } + freeStream (si); + } +} + +static int32_t writeStream (gpointer p, char *buf, uint32_t count) { + int32_t sz = -1; + StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); + /*print ("writeStream found %d count %d\n", !!si, count);*/ + if (si) { + if (si->reason > NPERR_NO_ERROR) { + sz = count; /* stream closed, skip remainings */ + } else { + if (!si->called_plugin) { + uint16 stype = NP_NORMAL; + NPError err = np_funcs.newstream (npp, si->mimetype + ? si->mimetype + : "text/plain", + &si->np_stream, 0, &stype); + if (err != NPERR_NO_ERROR) { + g_printerr ("newstream error %d\n", err); + destroyStream (p); + return count; /* stream not accepted, skip remainings */ + } + print ("newStream %d type:%d\n", (long) p, stype); + si->called_plugin = true; + } + if (count) /* urls with a target returns zero bytes */ + sz = np_funcs.writeready (npp, &si->np_stream); + if (sz > 0) { + sz = np_funcs.write (npp, &si->np_stream, si->stream_pos, + (int32_t) count > sz ? sz : (int32_t) count, buf); + if (sz < 0) /*FIXME plugin destroys stream here*/ + g_timeout_add (0, destroyStream, p); + } else { + sz = 0; + } + si->stream_pos += sz; + if (si->stream_pos == si->total) { + if (si->stream_pos || !count) + removeStream (p); + else + g_timeout_add (0, destroyStream, p); + } + } + } + return sz; +} + +static StreamInfo *addStream (const char *url, const char *mime, const char *target, void *notify_data, bool notify) { + StreamInfo *si = (StreamInfo *) malloc (sizeof (StreamInfo)); + + memset (si, 0, sizeof (StreamInfo)); + si->url = g_strdup (url); + si->np_stream.url = si->url; + if (mime) + si->mimetype = g_strdup (mime); + if (target) + si->target = g_strdup (target); + si->np_stream.notifyData = notify_data; + si->notify = notify; + si->np_stream.ndata = (void *) (long) (stream_id_counter++); + print ("add stream %d\n", (long) si->np_stream.ndata); + g_tree_insert (stream_list, si->np_stream.ndata, si); + + g_timeout_add (0, requestStream, si->np_stream.ndata); + + return si; +} + +/*----------------%<---------------------------------------------------------*/ + +static void createJsName (JsObject * obj, char **name, uint32_t * len) { + int slen = strlen (obj->name); + if (obj->parent) { + *len += slen + 1; + createJsName (obj->parent, name, len); + } else { + *name = (char *) malloc (*len + slen + 1); + *(*name + *len + slen) = 0; + *len = 0; + } + if (obj->parent) { + *(*name + *len) = '.'; + *len += 1; + } + memcpy (*name + *len, obj->name, slen); + *len += slen; +} + +static char *nsVariant2Str (const NPVariant *value) { + char *str; + switch (value->type) { + case NPVariantType_String: + str = (char *) malloc (value->value.stringValue.utf8length + 3); + sprintf (str, "'%s'", value->value.stringValue.utf8characters); + break; + case NPVariantType_Int32: + str = (char *) malloc (16); + snprintf (str, 15, "%d", value->value.intValue); + break; + case NPVariantType_Double: + str = (char *) malloc (64); + snprintf (str, 63, "%f", value->value.doubleValue); + break; + case NPVariantType_Bool: + str = strdup (value->value.boolValue ? "true" : "false"); + break; + case NPVariantType_Null: + str = strdup ("null"); + break; + case NPVariantType_Object: + if (&js_class == value->value.objectValue->_class) { + JsObject *jv = (JsObject *) value->value.objectValue; + char *val; + uint32_t vlen = 0; + createJsName (jv, &val, &vlen); + str = strdup (val); + free (val); + } + break; + default: + str = strdup (""); + break; + } + return str; +} + +/*----------------%<---------------------------------------------------------*/ + +static NPObject * nsCreateObject (NPP instance, NPClass *aClass) { + NPObject *obj; + if (aClass && aClass->allocate) { + obj = aClass->allocate (instance, aClass); + } else { + obj = (NPObject *) malloc (sizeof (NPObject)); + memset (obj, 0, sizeof (NPObject)); + obj->_class = aClass; + /*obj = js_class.allocate (instance, &js_class);/ *add null class*/ + print ("NPN_CreateObject\n"); + } + obj->referenceCount = 1; + return obj; +} + +static NPObject *nsRetainObject (NPObject *npobj) { + /*print( "nsRetainObject %p\n", npobj);*/ + npobj->referenceCount++; + return npobj; +} + +static void nsReleaseObject (NPObject *obj) { + /*print ("NPN_ReleaseObject\n");*/ + if (! (--obj->referenceCount)) + obj->_class->deallocate (obj); +} + +static NPError nsGetURL (NPP instance, const char* url, const char* target) { + (void)instance; + print ("nsGetURL %s %s\n", url, target ? target : ""); + addStream (url, 0L, target, 0L, false); + return NPERR_NO_ERROR; +} + +static NPError nsPostURL (NPP instance, const char *url, + const char *target, uint32 len, const char *buf, NPBool file) { + (void)instance; (void)len; (void)buf; (void)file; + print ("nsPostURL %s %s\n", url, target ? target : ""); + addStream (url, 0L, target, 0L, false); + return NPERR_NO_ERROR; +} + +static NPError nsRequestRead (NPStream *stream, NPByteRange *rangeList) { + (void)stream; (void)rangeList; + print ("nsRequestRead\n"); + return NPERR_NO_ERROR; +} + +static NPError nsNewStream (NPP instance, NPMIMEType type, + const char *target, NPStream **stream) { + (void)instance; (void)type; (void)stream; (void)target; + print ("nsNewStream\n"); + return NPERR_NO_ERROR; +} + +static int32 nsWrite (NPP instance, NPStream* stream, int32 len, void *buf) { + (void)instance; (void)len; (void)buf; (void)stream; + print ("nsWrite\n"); + return 0; +} + +static NPError nsDestroyStream (NPP instance, NPStream *stream, NPError reason) { + StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, stream->ndata); + (void)instance; + print ("nsDestroyStream\n"); + if (si) { + si->reason = reason; + si->destroyed = true; + g_timeout_add (0, destroyStream, stream->ndata); + return NPERR_NO_ERROR; + } + return NPERR_NO_DATA; +} + +static void nsStatus (NPP instance, const char* message) { + (void)instance; + print ("NPN_Status %s\n", message ? message : "-"); +} + +static const char* nsUserAgent (NPP instance) { + (void)instance; + print ("NPN_UserAgent\n"); + return ""; +} + +static void *nsAlloc (uint32 size) { + return malloc (size); +} + +static void nsMemFree (void* ptr) { + free (ptr); +} + +static uint32 nsMemFlush (uint32 size) { + (void)size; + print ("NPN_MemFlush\n"); + return 0; +} + +static void nsReloadPlugins (NPBool reloadPages) { + (void)reloadPages; + print ("NPN_ReloadPlugins\n"); +} + +static JRIEnv* nsGetJavaEnv () { + print ("NPN_GetJavaEnv\n"); + return NULL; +} + +static jref nsGetJavaPeer (NPP instance) { + (void)instance; + print ("NPN_GetJavaPeer\n"); + return NULL; +} + +static NPError nsGetURLNotify (NPP instance, const char* url, const char* target, void *notify) { + (void)instance; + print ("NPN_GetURLNotify %s %s\n", url, target ? target : ""); + addStream (url, 0L, target, notify, true); + return NPERR_NO_ERROR; +} + +static NPError nsPostURLNotify (NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file, void *notify) { + (void)instance; (void)len; (void)buf; (void)file; + print ("NPN_PostURLNotify\n"); + addStream (url, 0L, target, notify, true); + return NPERR_NO_ERROR; +} + +static NPError nsGetValue (NPP instance, NPNVariable variable, void *value) { + print ("NPN_GetValue %d\n", variable & ~NP_ABI_MASK); + switch (variable) { + case NPNVxDisplay: + *(void**)value = (void*)(long) gdk_x11_get_default_xdisplay (); + break; + case NPNVxtAppContext: + *(void**)value = NULL; + break; + case NPNVnetscapeWindow: + print ("NPNVnetscapeWindow\n"); + break; + case NPNVjavascriptEnabledBool: + *(int*)value = 1; + break; + case NPNVasdEnabledBool: + *(int*)value = 0; + break; + case NPNVisOfflineBool: + *(int*)value = 0; + break; + case NPNVserviceManager: + *(int*)value = 0; + break; + case NPNVToolkit: + *(int*)value = NPNVGtk2; + break; + case NPNVSupportsXEmbedBool: + *(int*)value = 1; + break; + case NPNVWindowNPObject: + if (!js_window) { + JsObject *jo = (JsObject*) nsCreateObject (instance, &js_class); + jo->name = g_strdup ("window"); + js_window = (NPObject *) jo; + } + *(NPObject**)value = nsRetainObject (js_window); + break; + case NPNVPluginElementNPObject: { + JsObject * obj = (JsObject *) nsCreateObject (instance, &js_class); + obj->name = g_strdup ("this"); + *(NPObject**)value = (NPObject *) obj; + break; + } + default: + *(int*)value = 0; + print ("unknown value\n"); + return NPERR_GENERIC_ERROR; + } + return NPERR_NO_ERROR; +} + +static NPError nsSetValue (NPP instance, NPPVariable variable, void *value) { + /* NPPVpluginWindowBool */ + (void)instance; (void)value; + print ("NPN_SetValue %d\n", variable & ~NP_ABI_MASK); + return NPERR_NO_ERROR; +} + +static void nsInvalidateRect (NPP instance, NPRect *invalidRect) { + (void)instance; (void)invalidRect; + print ("NPN_InvalidateRect\n"); +} + +static void nsInvalidateRegion (NPP instance, NPRegion invalidRegion) { + (void)instance; (void)invalidRegion; + print ("NPN_InvalidateRegion\n"); +} + +static void nsForceRedraw (NPP instance) { + (void)instance; + print ("NPN_ForceRedraw\n"); +} + +static NPIdentifier nsGetStringIdentifier (const NPUTF8* name) { + /*print ("NPN_GetStringIdentifier %s\n", name);*/ + gpointer id = g_tree_lookup (identifiers, name); + if (!id) { + id = strdup (name); + g_tree_insert (identifiers, id, id); + } + return id; +} + +static void nsGetStringIdentifiers (const NPUTF8** names, int32_t nameCount, + NPIdentifier* ids) { + (void)names; (void)nameCount; (void)ids; + print ("NPN_GetStringIdentifiers\n"); +} + +static NPIdentifier nsGetIntIdentifier (int32_t intid) { + print ("NPN_GetIntIdentifier %d\n", intid); + return (NPIdentifier) (long) intid; +} + +static bool nsIdentifierIsString (NPIdentifier name) { + print ("NPN_IdentifierIsString\n"); + return !!g_tree_lookup (identifiers, name); +} + +static NPUTF8 * nsUTF8FromIdentifier (NPIdentifier name) { + print ("NPN_UTF8FromIdentifier\n"); + char *str = g_tree_lookup (identifiers, name); + if (str) + return strdup (str); + return NULL; +} + +static int32_t nsIntFromIdentifier (NPIdentifier identifier) { + print ("NPN_IntFromIdentifier\n"); + return (int32_t) (long) identifier; +} + +static bool nsInvoke (NPP instance, NPObject * npobj, NPIdentifier method, + const NPVariant *args, uint32_t arg_count, NPVariant *result) { + (void)instance; + /*print ("NPN_Invoke %s\n", id);*/ + return npobj->_class->invoke (npobj, method, args, arg_count, result); +} + +static bool nsInvokeDefault (NPP instance, NPObject * npobj, + const NPVariant * args, uint32_t arg_count, NPVariant * result) { + (void)instance; + return npobj->_class->invokeDefault (npobj,args, arg_count, result); +} + +static bool nsEvaluate (NPP instance, NPObject * npobj, NPString * script, + NPVariant * result) { + char * this_var; + char * this_var_type; + char * this_var_string; + char * jsscript; + (void) npobj; /*FIXME scope, search npobj window*/ + print ("NPN_Evaluate:"); + + /* assign to a js variable */ + this_var = (char *) malloc (64); + sprintf (this_var, "this.__kmplayer__obj_%d", js_obj_counter); + + jsscript = (char *) malloc (strlen (this_var) + script->utf8length + 3); + sprintf (jsscript, "%s=%s;", this_var, script->utf8characters); + this_var_string = evaluate (jsscript); + free (jsscript); + + if (this_var_string) { + /* get type of js this_var */ + jsscript = (char *) malloc (strlen (this_var) + 9); + sprintf (jsscript, "typeof %s;", this_var); + this_var_type = evaluate (jsscript); + free (jsscript); + + if (this_var_type) { + if (!strcasecmp (this_var_type, "undefined")) { + result->type = NPVariantType_Null; + } else if (!strcasecmp (this_var_type, "object")) { + JsObject *jo = (JsObject *)nsCreateObject (instance, &js_class); + js_obj_counter++; + result->type = NPVariantType_Object; + jo->name = g_strdup (this_var); + result->value.objectValue = (NPObject *)jo; + } else { /* FIXME numbers/void/undefined*/ + result->type = NPVariantType_String; + result->value.stringValue.utf8characters = + g_strdup (this_var_string); + result->value.stringValue.utf8length=strlen (this_var_string)+1; + } + g_free (this_var_type); + } + g_free (this_var_string); + } else { + print (" => error\n"); + return false; + } + free (this_var); + + return true; +} + +static bool nsGetProperty (NPP instance, NPObject * npobj, + NPIdentifier property, NPVariant * result) { + (void)instance; + return npobj->_class->getProperty (npobj, property, result); +} + +static bool nsSetProperty (NPP instance, NPObject * npobj, + NPIdentifier property, const NPVariant *value) { + (void)instance; + return npobj->_class->setProperty (npobj, property, value); +} + +static bool nsRemoveProperty (NPP inst, NPObject * npobj, NPIdentifier prop) { + (void)inst; + return npobj->_class->removeProperty (npobj, prop); +} + +static bool nsHasProperty (NPP instance, NPObject * npobj, NPIdentifier prop) { + (void)instance; + return npobj->_class->hasProperty (npobj, prop); +} + +static bool nsHasMethod (NPP instance, NPObject * npobj, NPIdentifier method) { + (void)instance; + return npobj->_class->hasMethod (npobj, method); +} + +static void nsReleaseVariantValue (NPVariant * variant) { + /*print ("NPN_ReleaseVariantValue\n");*/ + switch (variant->type) { + case NPVariantType_String: + if (variant->value.stringValue.utf8characters) + g_free ((char *) variant->value.stringValue.utf8characters); + break; + case NPVariantType_Object: + if (variant->value.objectValue) + nsReleaseObject (variant->value.objectValue); + break; + default: + break; + } + variant->type = NPVariantType_Null; +} + +static void nsSetException (NPObject *npobj, const NPUTF8 *message) { + (void)npobj; + print ("NPN_SetException %s\n", message ? message : "-"); +} + +static bool nsPushPopupsEnabledState (NPP instance, NPBool enabled) { + (void)instance; + print ("NPN_PushPopupsEnabledState %d\n", enabled); + return false; +} + +static bool nsPopPopupsEnabledState (NPP instance) { + (void)instance; + print ("NPN_PopPopupsEnabledState\n"); + return false; +} + +/*----------------%<---------------------------------------------------------*/ + +static NPObject * windowClassAllocate (NPP instance, NPClass *aClass) { + (void)instance; + /*print ("windowClassAllocate\n");*/ + JsObject * jo = (JsObject *) malloc (sizeof (JsObject)); + memset (jo, 0, sizeof (JsObject)); + jo->npobject._class = aClass; + return (NPObject *) jo; +} + +static void windowClassDeallocate (NPObject *npobj) { + JsObject *jo = (JsObject *) npobj; + /*print ("windowClassDeallocate\n");*/ + if (jo->parent) { + nsReleaseObject ((NPObject *) jo->parent); + } else if (jo->name && !strncmp (jo->name, "this.__kmplayer__obj_", 21)) { + char *script = (char *) malloc (strlen (jo->name) + 7); + char *result; + char *counter = strrchr (jo->name, '_'); + sprintf (script, "%s=null;", jo->name); + result = evaluate (script); + free (script); + g_free (result); + if (counter) { + int c = strtol (counter +1, NULL, 10); + if (c == js_obj_counter -1) + js_obj_counter--; /*poor man's variable name reuse */ + } + } + if (jo->name) + g_free (jo->name); + if (npobj == js_window) { + print ("WARNING deleting window object\n"); + js_window = NULL; + } + free (npobj); +} + +static void windowClassInvalidate (NPObject *npobj) { + (void)npobj; + print ("windowClassInvalidate\n"); +} + +static bool windowClassHasMethod (NPObject *npobj, NPIdentifier name) { + (void)npobj; (void)name; + print ("windowClassHasMehtod\n"); + return false; +} + +static bool windowClassInvoke (NPObject *npobj, NPIdentifier method, + const NPVariant *args, uint32_t arg_count, NPVariant *result) { + JsObject * jo = (JsObject *) npobj; + NPString str = { NULL, 0 }; + char buf[512]; + int pos, i; + bool res; + char * id = (char *) g_tree_lookup (identifiers, method); + /*print ("windowClassInvoke\n");*/ + + result->type = NPVariantType_Null; + result->value.objectValue = NULL; + + if (!id) { + print ("Invoke invalid id\n"); + return false; + } + print ("Invoke %s\n", id); + createJsName (jo, (char **)&str.utf8characters, &str.utf8length); + pos = snprintf (buf, sizeof (buf), "%s.%s(", str.utf8characters, id); + free ((char *) str.utf8characters); + for (i = 0; i < arg_count; i++) { + char *arg = nsVariant2Str (args + i); + pos += snprintf (buf + pos, sizeof (buf) - pos, i ? ",%s" : "%s", arg); + free (arg); + } + pos += snprintf (buf + pos, sizeof (buf) - pos, ")"); + + str.utf8characters = buf; + str.utf8length = pos; + res = nsEvaluate (npp, npobj, &str, result); + + return true; +} + +static bool windowClassInvokeDefault (NPObject *npobj, + const NPVariant *args, uint32_t arg_count, NPVariant *result) { + (void)npobj; (void)args; (void)arg_count; (void)result; + print ("windowClassInvokeDefault\n"); + return false; +} + +static bool windowClassHasProperty (NPObject *npobj, NPIdentifier name) { + (void)npobj; (void)name; + print ("windowClassHasProperty\n"); + return false; +} + +static bool windowClassGetProperty (NPObject *npobj, NPIdentifier property, + NPVariant *result) { + char * id = (char *) g_tree_lookup (identifiers, property); + JsObject jo; + NPString fullname = { NULL, 0 }; + bool res; + + print ("GetProperty %s\n", id); + result->type = NPVariantType_Null; + result->value.objectValue = NULL; + + if (!id) + return false; + + if (!strcmp (((JsObject *) npobj)->name, "window") && + !strcmp (id, "top")) { + result->type = NPVariantType_Object; + result->value.objectValue = nsRetainObject (js_window); + return true; + } + + jo.name = id; + jo.parent = (JsObject *) npobj; + createJsName (&jo, (char **)&fullname.utf8characters, &fullname.utf8length); + + res = nsEvaluate (npp, npobj, &fullname, result); + + free ((char *) fullname.utf8characters); + + return res; +} + +static bool windowClassSetProperty (NPObject *npobj, NPIdentifier property, + const NPVariant *value) { + char *id = (char *) g_tree_lookup (identifiers, property); + char *script, *var_name, *var_val, *res; + JsObject jo; + uint32_t len = 0; + + if (!id) + return false; + + jo.name = id; + jo.parent = (JsObject *) npobj; + createJsName (&jo, &var_name, &len); + + var_val = nsVariant2Str (value); + script = (char *) malloc (len + strlen (var_val) + 3); + sprintf (script, "%s=%s;", var_name, var_val); + free (var_name); + free (var_val); + print ("SetProperty %s\n", script); + + res = evaluate (script); + if (res) + g_free (res); + free (script); + + + return true; +} + +static bool windowClassRemoveProperty (NPObject *npobj, NPIdentifier name) { + (void)npobj; (void)name; + print ("windowClassRemoveProperty\n"); + return false; +} + + +/*----------------%<---------------------------------------------------------*/ + +static void shutDownPlugin() { + if (scriptable_peer) { + nsReleaseObject (scriptable_peer); + scriptable_peer = NULL; + } + if (npShutdown) { + if (npp) { + np_funcs.destroy (npp, &saved_data); + free (npp); + npp = 0L; + } + npShutdown(); + npShutdown = 0; + } +} + +static void readStdin (gpointer p, gint src, GdkInputCondition cond) { + char *buf_ptr = stream_buf; + gsize bytes_read = read (src, + stream_buf + stream_buf_pos, + sizeof (stream_buf) - stream_buf_pos); + (void)cond; (void)p; + if (bytes_read > 0) + stream_buf_pos += bytes_read; + + /*print ("readStdin %d\n", bytes_read);*/ + while (buf_ptr < stream_buf + stream_buf_pos) { + uint32_t write_len; + int32_t bytes_written; + + if (callback_service && !stream_chunk_size) { + /* read header info */ + if (stream_buf + stream_buf_pos < buf_ptr + 2 * sizeof (uint32_t)) + break; /* need more data */ + current_stream_id = (gpointer)(long)*(uint32_t*)(buf_ptr); + stream_chunk_size = *((uint32_t *)(buf_ptr + sizeof (uint32_t))); + /*print ("header %d %d\n",(long)current_stream_id, stream_chunk_size);*/ + buf_ptr += 2 * sizeof (uint32_t); + if (stream_chunk_size && stream_buf + stream_buf_pos == buf_ptr) { + stream_buf_pos = 0; + break; /* only read the header for chunk with data */ + } + } + /* feed it to the stream */ + write_len = stream_buf + stream_buf_pos - buf_ptr; + if (callback_service && write_len > stream_chunk_size) + write_len = stream_chunk_size; + bytes_written = writeStream (current_stream_id, buf_ptr, write_len); + if (bytes_written < 0) { + print ("couldn't write to stream %d\n", (long)current_stream_id); + bytes_written = write_len; /* assume stream destroyed, skip */ + } + + /* update chunk status */ + if (bytes_written > 0) { + buf_ptr += bytes_written; + /*print ("update chunk %d %d\n", bytes_written, stream_chunk_size);*/ + stream_chunk_size -= bytes_written; + } else { + /* FIXME if plugin didn't accept the data retry later, suspend stdin reading */ + break; + } + + } + /* update buffer */ + /*print ("buffer written:%d bufpos:%d\n", buf_ptr-stream_buf, stream_buf_pos);*/ + if (stream_buf + stream_buf_pos == buf_ptr) { + stream_buf_pos = 0; + } else { + g_assert (buf_ptr < stream_buf + stream_buf_pos); + stream_buf_pos -= (stream_buf + stream_buf_pos - buf_ptr); + memmove (stream_buf, buf_ptr, stream_buf_pos); + } + if (bytes_read <= 0) { /* eof of stdin, only for 'cat foo | knpplayer' */ + StreamInfo*si=(StreamInfo*)g_tree_lookup(stream_list,current_stream_id); + si->reason = NPRES_DONE; + removeStream (current_stream_id); + if (stdin_read_watch) { + gdk_input_remove (stdin_read_watch); + stdin_read_watch = 0; + } + } +} + +static int initPlugin (const char *plugin_lib) { + NPNetscapeFuncs ns_funcs; + NPError np_err; + char *pname; + + print ("starting %s with %s\n", plugin_lib, object_url); + library = g_module_open (plugin_lib, G_MODULE_BIND_LAZY); + if (!library) { + print ("failed to load %s\n", plugin_lib); + return -1; + } + if (!g_module_symbol (library, + "NP_GetMIMEDescription", (gpointer *)&npGetMIMEDescription)) { + print ("undefined reference to load NP_GetMIMEDescription\n"); + return -1; + } + if (!g_module_symbol (library, + "NP_GetValue", (gpointer *)&npGetValue)) { + print ("undefined reference to load NP_GetValue\n"); + } + if (!g_module_symbol (library, + "NP_Initialize", (gpointer *)&npInitialize)) { + print ("undefined reference to load NP_Initialize\n"); + return -1; + } + if (!g_module_symbol (library, + "NP_Shutdown", (gpointer *)&npShutdown)) { + print ("undefined reference to load NP_Shutdown\n"); + return -1; + } + print ("startup succeeded %s\n", npGetMIMEDescription ()); + memset (&ns_funcs, 0, sizeof (NPNetscapeFuncs)); + ns_funcs.size = sizeof (NPNetscapeFuncs); + ns_funcs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; + ns_funcs.geturl = nsGetURL; + ns_funcs.posturl = nsPostURL; + ns_funcs.requestread = nsRequestRead; + ns_funcs.newstream = nsNewStream; + ns_funcs.write = nsWrite; + ns_funcs.destroystream = nsDestroyStream; + ns_funcs.status = nsStatus; + ns_funcs.uagent = nsUserAgent; + ns_funcs.memalloc = nsAlloc; + ns_funcs.memfree = nsMemFree; + ns_funcs.memflush = nsMemFlush; + ns_funcs.reloadplugins = nsReloadPlugins; + ns_funcs.getJavaEnv = nsGetJavaEnv; + ns_funcs.getJavaPeer = nsGetJavaPeer; + ns_funcs.geturlnotify = nsGetURLNotify; + ns_funcs.posturlnotify = nsPostURLNotify; + ns_funcs.getvalue = nsGetValue; + ns_funcs.setvalue = nsSetValue; + ns_funcs.invalidaterect = nsInvalidateRect; + ns_funcs.invalidateregion = nsInvalidateRegion; + ns_funcs.forceredraw = nsForceRedraw; + ns_funcs.getstringidentifier = nsGetStringIdentifier; + ns_funcs.getstringidentifiers = nsGetStringIdentifiers; + ns_funcs.getintidentifier = nsGetIntIdentifier; + ns_funcs.identifierisstring = nsIdentifierIsString; + ns_funcs.utf8fromidentifier = nsUTF8FromIdentifier; + ns_funcs.intfromidentifier = nsIntFromIdentifier; + ns_funcs.createobject = nsCreateObject; + ns_funcs.retainobject = nsRetainObject; + ns_funcs.releaseobject = nsReleaseObject; + ns_funcs.invoke = nsInvoke; + ns_funcs.invokeDefault = nsInvokeDefault; + ns_funcs.evaluate = nsEvaluate; + ns_funcs.getproperty = nsGetProperty; + ns_funcs.setproperty = nsSetProperty; + ns_funcs.removeproperty = nsRemoveProperty; + ns_funcs.hasproperty = nsHasProperty; + ns_funcs.hasmethod = nsHasMethod; + ns_funcs.releasevariantvalue = nsReleaseVariantValue; + ns_funcs.setexception = nsSetException; + ns_funcs.pushpopupsenabledstate = nsPushPopupsEnabledState; + ns_funcs.poppopupsenabledstate = nsPopPopupsEnabledState; + + js_class.structVersion = NP_CLASS_STRUCT_VERSION; + js_class.allocate = windowClassAllocate; + js_class.deallocate = windowClassDeallocate; + js_class.invalidate = windowClassInvalidate; + js_class.hasMethod = windowClassHasMethod; + js_class.invoke = windowClassInvoke; + js_class.invokeDefault = windowClassInvokeDefault; + js_class.hasProperty = windowClassHasProperty; + js_class.getProperty = windowClassGetProperty; + js_class.setProperty = windowClassSetProperty; + js_class.removeProperty = windowClassRemoveProperty; + + np_funcs.size = sizeof (NPPluginFuncs); + + np_err = npInitialize (&ns_funcs, &np_funcs); + if (np_err != NPERR_NO_ERROR) { + print ("NP_Initialize failure %d\n", np_err); + npShutdown = 0; + return -1; + } + np_err = npGetValue (NULL, NPPVpluginNameString, &pname); + if (np_err == NPERR_NO_ERROR) + print ("NP_GetValue Name %s\n", pname); + np_err = npGetValue (NULL, NPPVpluginDescriptionString, &pname); + if (np_err == NPERR_NO_ERROR) + print ("NP_GetValue Description %s\n", pname); + return 0; +} + +static int newPlugin (NPMIMEType mime, int16 argc, char *argn[], char *argv[]) { + NPSetWindowCallbackStruct ws_info; + NPError np_err; + Display *display; + int screen; + int i; + int needs_xembed; + uint32_t width = 0, height = 0; + + for (i = 0; i < argc; i++) { + if (!strcasecmp (argn[i], "width")) + width = strtol (argv[i], 0L, 10); + else if (!strcasecmp (argn[i], "height")) + height = strtol (argv[i], 0L, 10); + } + if (width > 0 && height > 0) + callFunction (-1, "dimension", + DBUS_TYPE_UINT32, &width, DBUS_TYPE_UINT32, &height, + DBUS_TYPE_INVALID); + + npp = (NPP_t*)malloc (sizeof (NPP_t)); + memset (npp, 0, sizeof (NPP_t)); + np_err = np_funcs.newp (mime, npp, NP_EMBED, argc, argn, argv, saved_data); + if (np_err != NPERR_NO_ERROR) { + print ("NPP_New failure %d %p %p\n", np_err, np_funcs, np_funcs.newp); + return -1; + } + if (np_funcs.getvalue) { + char *pname; + void *iid; + np_err = np_funcs.getvalue ((void*)npp, + NPPVpluginNameString, (void*)&pname); + if (np_err == NPERR_NO_ERROR) + print ("plugin name %s\n", pname); + np_err = np_funcs.getvalue ((void*)npp, + NPPVpluginNeedsXEmbed, (void*)&needs_xembed); + if (np_err != NPERR_NO_ERROR || !needs_xembed) { + print ("NPP_GetValue NPPVpluginNeedsXEmbed failure %d\n", np_err); + shutDownPlugin(); + return -1; + } + np_err = np_funcs.getvalue ((void*)npp, + NPPVpluginScriptableIID, (void*)&iid); + np_err = np_funcs.getvalue ((void*)npp, + NPPVpluginScriptableNPObject, (void*)&scriptable_peer); + if (np_err != NPERR_NO_ERROR || !scriptable_peer) + print ("NPP_GetValue no NPPVpluginScriptableNPObject %d\n", np_err); + } + memset (&np_window, 0, sizeof (NPWindow)); + display = gdk_x11_get_default_xdisplay (); + np_window.x = 0; + np_window.y = 0; + np_window.width = 1920; + np_window.height = 1200; + np_window.window = (void*)socket_id; + np_window.type = NPWindowTypeWindow; + ws_info.type = NP_SETWINDOW; + screen = DefaultScreen (display); + ws_info.display = (void*)(long)display; + ws_info.visual = (void*)(long)DefaultVisual (display, screen); + ws_info.colormap = DefaultColormap (display, screen); + ws_info.depth = DefaultDepth (display, screen); + print ("display %u %dx%d\n", socket_id, width, height); + np_window.ws_info = (void*)&ws_info; + + GtkAllocation allocation; + allocation.x = 0; + allocation.y = 0; + allocation.width = np_window.width; + allocation.height = np_window.height; + gtk_widget_size_allocate (xembed, &allocation); + + np_err = np_funcs.setwindow (npp, &np_window); + + return 0; +} + +static gpointer startPlugin (const char *url, const char *mime, + int argc, char *argn[], char *argv[]) { + StreamInfo *si; + if (!npp && (initPlugin (plugin) || newPlugin (mimetype, argc, argn, argv))) + return 0L; + si = addStream (url, mime, 0L, 0L, false); + return si; +} + +/*----------------%<---------------------------------------------------------*/ + +static StreamInfo *getStreamInfo (const char *path, gpointer *stream_id) { + const char *p = strrchr (path, '_'); + *stream_id = p ? (gpointer) strtol (p+1, NULL, 10) : NULL; + return (StreamInfo *) g_tree_lookup (stream_list, *stream_id); +} + +static DBusHandlerResult dbusFilter (DBusConnection * connection, + DBusMessage *msg, void * user_data) { + DBusMessageIter args; + const char *sender = dbus_message_get_sender (msg); + const char *iface = "org.kde.kmplayer.backend"; + (void)user_data; (void)connection; + if (!dbus_message_has_destination (msg, service_name)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + print ("dbusFilter %s %s\n", sender,dbus_message_get_interface (msg)); + if (dbus_message_is_method_call (msg, iface, "play")) { + DBusMessageIter ait; + char *param = 0; + unsigned int params; + char **argn = NULL; + char **argv = NULL; + int i; + if (!dbus_message_iter_init (msg, &args) || + DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&args)) { + g_printerr ("missing url arg"); + return DBUS_HANDLER_RESULT_HANDLED; + } + dbus_message_iter_get_basic (&args, ¶m); + object_url = g_strdup (param); + if (!dbus_message_iter_next (&args) || + DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&args)) { + g_printerr ("missing mimetype arg"); + return DBUS_HANDLER_RESULT_HANDLED; + } + dbus_message_iter_get_basic (&args, ¶m); + mimetype = g_strdup (param); + if (!dbus_message_iter_next (&args) || + DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&args)) { + g_printerr ("missing plugin arg"); + return DBUS_HANDLER_RESULT_HANDLED; + } + dbus_message_iter_get_basic (&args, ¶m); + plugin = g_strdup (param); + if (!dbus_message_iter_next (&args) || + DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type (&args)) { + g_printerr ("missing param count arg"); + return DBUS_HANDLER_RESULT_HANDLED; + } + dbus_message_iter_get_basic (&args, ¶ms); + if (params > 0 && params < 100) { + argn = (char**) malloc (params * sizeof (char *)); + argv = (char**) malloc (params * sizeof (char *)); + } + if (!dbus_message_iter_next (&args) || + DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type (&args)) { + g_printerr ("missing params array"); + return DBUS_HANDLER_RESULT_HANDLED; + } + dbus_message_iter_recurse (&args, &ait); + for (i = 0; i < params; i++) { + char *key, *value; + DBusMessageIter di; + if (dbus_message_iter_get_arg_type (&ait) != DBUS_TYPE_DICT_ENTRY) + break; + dbus_message_iter_recurse (&ait, &di); + if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&di)) + break; + dbus_message_iter_get_basic (&di, &key); + if (!dbus_message_iter_next (&di) || + DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&di)) + break; + dbus_message_iter_get_basic (&di, &value); + argn[i] = g_strdup (key); + argv[i] = g_strdup (value); + print ("param %d:%s='%s'\n", i + 1, argn[i], value); + if (!dbus_message_iter_next (&ait)) + params = i + 1; + } + print ("play %s %s %s params:%d\n", object_url, + mimetype ? mimetype : "", plugin, i); + startPlugin (object_url, mimetype, i, argn, argv); + } else if (dbus_message_is_method_call (msg, iface, "redirected")) { + char *url = 0; + gpointer stream_id; + StreamInfo *si = getStreamInfo(dbus_message_get_path (msg), &stream_id); + if (si && dbus_message_iter_init (msg, &args) && + DBUS_TYPE_STRING == dbus_message_iter_get_arg_type (&args)) { + dbus_message_iter_get_basic (&args, &url); + free (si->url); + si->url = g_strdup (url); + si->np_stream.url = si->url; + print ("redirect %d (had data %d) to %s\n", (long)stream_id, si->called_plugin, url); + } + } else if (dbus_message_is_method_call (msg, iface, "eof")) { + gpointer stream_id; + StreamInfo *si = getStreamInfo(dbus_message_get_path (msg), &stream_id); + if (si && dbus_message_iter_init (msg, &args) && + DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type (&args)) { + dbus_message_iter_get_basic (&args, &si->total); + if (dbus_message_iter_next (&args) && + DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type (&args)) { + dbus_message_iter_get_basic (&args, &si->reason); + print ("eof %d bytes:%d reason:%d\n", (long)stream_id, si->total, si->reason); + if (si->stream_pos == si->total || si->destroyed) + removeStream (stream_id); + } + } + } else if (dbus_message_is_method_call (msg, iface, "quit")) { + print ("quit\n"); + shutDownPlugin(); + gtk_main_quit(); + } else if (dbus_message_is_method_call (msg, iface, "streamInfo")) { + gpointer stream_id; + StreamInfo *si = getStreamInfo(dbus_message_get_path (msg), &stream_id); + const char *mime; + uint32_t length; + if (si && dbus_message_iter_init (msg, &args) && + DBUS_TYPE_STRING == dbus_message_iter_get_arg_type (&args)) { + dbus_message_iter_get_basic (&args, &mime); + if (*mime) { + if (si->mimetype) + g_free (si->mimetype); + si->mimetype = g_strdup (mime); + } + if (dbus_message_iter_next (&args) && + DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type (&args)) { + dbus_message_iter_get_basic (&args, &length); + si->np_stream.end = length; + } + print ("streamInfo %d size:%d mime:%s\n", (long)stream_id, length, + mime ? mime : ""); + } + } else { + print ("unknown message\n"); + } + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void callFunction(int stream,const char *func, int first_arg_type, ...) { + char path[64]; + strncpy (path, callback_path, sizeof (path) -1); + if (stream > -1) { + int len = strlen (path); + snprintf (path + len, sizeof (path) - len, "/stream_%d", stream); + } + print ("call %s.%s()\n", path, func); + if (callback_service) { + va_list var_args; + DBusMessage *msg = dbus_message_new_method_call ( + callback_service, + path, + "org.kde.kmplayer.callback", + func); + if (first_arg_type != DBUS_TYPE_INVALID) { + va_start (var_args, first_arg_type); + dbus_message_append_args_valist (msg, first_arg_type, var_args); + va_end (var_args); + } + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (dbus_connection, msg, NULL); + dbus_message_unref (msg); + dbus_connection_flush (dbus_connection); + } +} + +static char * evaluate (const char *script) { + char * ret = NULL; + print ("evaluate %s", script); + if (callback_service) { + DBusMessage *rmsg; + DBusMessage *msg = dbus_message_new_method_call ( + callback_service, + callback_path, + "org.kde.kmplayer.callback", + "evaluate"); + dbus_message_append_args ( + msg, DBUS_TYPE_STRING, &script, DBUS_TYPE_INVALID); + rmsg = dbus_connection_send_with_reply_and_block (dbus_connection, + msg, 2000, NULL); + if (rmsg) { + DBusMessageIter it; + if (dbus_message_iter_init (rmsg, &it) && + DBUS_TYPE_STRING == dbus_message_iter_get_arg_type (&it)) { + char * param; + dbus_message_iter_get_basic (&it, ¶m); + ret = g_strdup (param); + } + dbus_message_unref (rmsg); + print (" => %s\n", ret); + } + dbus_message_unref (msg); + } else { + print (" => NA\n"); + } + return ret; +} + +/*----------------%<---------------------------------------------------------*/ + +static void pluginAdded (GtkSocket *socket, gpointer d) { + /*(void)socket;*/ (void)d; + print ("pluginAdded\n"); + if (socket->plug_window) { + gpointer user_data = NULL; + gdk_window_get_user_data (socket->plug_window, &user_data); + if (!user_data) { + /** + * GtkSocket resets plugins XSelectInput in + * _gtk_socket_add_window + * _gtk_socket_windowing_select_plug_window_input + **/ + XSelectInput (gdk_x11_get_default_xdisplay (), + gdk_x11_drawable_get_xid (socket->plug_window), + KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | + KeymapStateMask | + ButtonMotionMask | + PointerMotionMask | + EnterWindowMask | LeaveWindowMask | + FocusChangeMask | + ExposureMask | + StructureNotifyMask | + SubstructureRedirectMask | + PropertyChangeMask + ); + } + } + callFunction (-1, "plugged", DBUS_TYPE_INVALID); +} + +static void windowCreatedEvent (GtkWidget *w, gpointer d) { + (void)d; + print ("windowCreatedEvent\n"); + socket_id = gtk_socket_get_id (GTK_SOCKET (xembed)); + if (parent_id) { + print ("windowCreatedEvent %p\n", GTK_PLUG (w)->socket_window); + if (!GTK_PLUG (w)->socket_window) + gtk_plug_construct (GTK_PLUG (w), parent_id); + gdk_window_reparent( w->window, + GTK_PLUG (w)->socket_window + ? GTK_PLUG (w)->socket_window + : gdk_window_foreign_new (parent_id), + 0, 0); + gtk_widget_show_all (w); + /*XReparentWindow (gdk_x11_drawable_get_xdisplay (w->window), + gdk_x11_drawable_get_xid (w->window), + parent_id, + 0, 0);*/ + } + if (!callback_service) { + char *argn[] = { "WIDTH", "HEIGHT", "debug", "SRC" }; + char *argv[] = { "440", "330", g_strdup("yes"), g_strdup(object_url) }; + startPlugin (object_url, mimetype, 4, argn, argv); + } +} + +static void embeddedEvent (GtkPlug *plug, gpointer d) { + (void)plug; (void)d; + print ("embeddedEvent\n"); +} + +static gboolean updateDimension (void * p) { + (void)p; + if (np_window.window) { + if (np_window.width != top_w || np_window.height != top_h) { + np_window.width = top_w; + np_window.height = top_h; + np_funcs.setwindow (npp, &np_window); + } + update_dimension_timer = 0; + return 0; /* single shot */ + } else { + return 1; + } +} + +static gboolean configureEvent(GtkWidget *w, GdkEventConfigure *e, gpointer d) { + (void)w; (void)d; + if (e->width != top_w || e->height != top_h) { + top_w = e->width; + top_h = e->height; + if (!update_dimension_timer) + update_dimension_timer = g_timeout_add (100, updateDimension, NULL); + } + return FALSE; +} + +static gboolean windowCloseEvent (GtkWidget *w, GdkEvent *e, gpointer d) { + (void)w; (void)e; (void)d; + shutDownPlugin(); + return FALSE; +} + +static void windowDestroyEvent (GtkWidget *w, gpointer d) { + (void)w; (void)d; + gtk_main_quit(); +} + +static gboolean initPlayer (void * p) { + GtkWidget *window; + GdkColormap *color_map; + GdkColor bg_color; + (void)p; + + window = callback_service + ? gtk_plug_new (parent_id) + : gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (G_OBJECT (window), "delete_event", + G_CALLBACK (windowCloseEvent), NULL); + g_signal_connect (G_OBJECT (window), "destroy", + G_CALLBACK (windowDestroyEvent), NULL); + g_signal_connect_after (G_OBJECT (window), "realize", + GTK_SIGNAL_FUNC (windowCreatedEvent), NULL); + g_signal_connect (G_OBJECT (window), "configure-event", + GTK_SIGNAL_FUNC (configureEvent), NULL); + + xembed = gtk_socket_new(); + g_signal_connect (G_OBJECT (xembed), "plug-added", + GTK_SIGNAL_FUNC (pluginAdded), NULL); + + color_map = gdk_colormap_get_system(); + gdk_colormap_query_color (color_map, 0, &bg_color); + gtk_widget_modify_bg (xembed, GTK_STATE_NORMAL, &bg_color); + + gtk_container_add (GTK_CONTAINER (window), xembed); + + if (!parent_id) { + gtk_widget_set_size_request (window, 440, 330); + gtk_widget_show_all (window); + } else { + g_signal_connect (G_OBJECT (window), "embedded", + GTK_SIGNAL_FUNC (embeddedEvent), NULL); + gtk_widget_set_size_request (window, 1920, 1200); + gtk_widget_realize (window); + } + + if (callback_service && callback_path) { + DBusError dberr; + const char *serv = "type='method_call',interface='org.kde.kmplayer.backend'"; + char myname[64]; + + dbus_error_init (&dberr); + dbus_connection = dbus_bus_get (DBUS_BUS_SESSION, &dberr); + if (!dbus_connection) { + g_printerr ("Failed to open connection to bus: %s\n", + dberr.message); + exit (1); + } + g_sprintf (myname, "org.kde.kmplayer.npplayer-%d", getpid ()); + service_name = g_strdup (myname); + print ("using service %s was '%s'\n", service_name, dbus_bus_get_unique_name (dbus_connection)); + dbus_connection_setup_with_g_main (dbus_connection, 0L); + dbus_bus_request_name (dbus_connection, service_name, + DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr); + if (dbus_error_is_set (&dberr)) { + g_printerr ("Failed to register name: %s\n", dberr.message); + dbus_connection_unref (dbus_connection); + return -1; + } + dbus_bus_add_match (dbus_connection, serv, &dberr); + if (dbus_error_is_set (&dberr)) { + g_printerr ("dbus_bus_add_match error: %s\n", dberr.message); + dbus_connection_unref (dbus_connection); + return -1; + } + dbus_connection_add_filter (dbus_connection, dbusFilter, 0L, 0L); + + /* TODO: remove DBUS_BUS_SESSION and create a private connection */ + callFunction (-1, "running", + DBUS_TYPE_STRING, &service_name, DBUS_TYPE_INVALID); + + dbus_connection_flush (dbus_connection); + } + return 0; /* single shot */ +} + +int main (int argc, char **argv) { + int i; + + XInitThreads (); + g_thread_init (NULL); + gtk_init (&argc, &argv); + + for (i = 1; i < argc; i++) { + if (!strcmp (argv[i], "-p") && ++i < argc) { + plugin = g_strdup (argv[i]); + } else if (!strcmp (argv[i], "-cb") && ++i < argc) { + gchar *cb = g_strdup (argv[i]); + gchar *path = strchr(cb, '/'); + if (path) { + callback_path = g_strdup (path); + *path = 0; + } + callback_service = g_strdup (cb); + g_free (cb); + } else if (!strcmp (argv[i], "-m") && ++i < argc) { + mimetype = g_strdup (argv[i]); + } else if (!strcmp (argv [i], "-wid") && ++i < argc) { + parent_id = strtol (argv[i], 0L, 10); + } else + object_url = g_strdup (argv[i]); + } + if (!callback_service && !(object_url && mimetype && plugin)) { + g_fprintf(stderr, "Usage: %s <-m mimetype -p plugin url|-cb service -wid id>\n", argv[0]); + return 1; + } + + identifiers = g_tree_new (strcmp); + stream_list = g_tree_new (streamCompare); + + g_timeout_add (0, initPlayer, NULL); + + fcntl (0, F_SETFL, fcntl (0, F_GETFL) | O_NONBLOCK); + + print ("entering gtk_main\n"); + + gtk_main(); + + if (dbus_connection) + dbus_connection_unref (dbus_connection); + + return 0; +} diff --git a/src/playlistview.cpp b/src/playlistview.cpp new file mode 100644 index 0000000..a7d5503 --- /dev/null +++ b/src/playlistview.cpp @@ -0,0 +1,720 @@ +/** + * Copyright (C) 2006 by Koos Vriezen <[email protected]> + * + * 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 <stdio.h> + +#include <config.h> +// include files for Qt +#include <qapplication.h> +#include <qclipboard.h> +#include <qpopupmenu.h> +#include <qdrawutil.h> +#include <qpainter.h> +#include <qiconset.h> +#include <qpixmap.h> +#include <qheader.h> +#include <qstyle.h> +#include <qtimer.h> + +#include <kiconloader.h> +#include <kfinddialog.h> +#include <kurldrag.h> +#include <kaction.h> +#include <klocale.h> +#include <kdebug.h> + +#include "playlistview.h" +#include "kmplayerview.h" +#include "kmplayercontrolpanel.h" + +using namespace KMPlayer; + +//------------------------------------------------------------------------- + +namespace KMPlayer { + + KDE_NO_EXPORT bool isDragValid (QDropEvent * de) { + if (KURLDrag::canDecode (de)) + return true; + if (QTextDrag::canDecode (de)) { + QString text; + if (QTextDrag::decode (de, text) && KURL (text).isValid ()) + return true; + } + return false; + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT PlayListItem::PlayListItem (QListViewItem *p, const NodePtr & e, PlayListView * lv) : QListViewItem (p), node (e), listview (lv) {} + +KDE_NO_CDTOR_EXPORT PlayListItem::PlayListItem (QListViewItem *p, const AttributePtr & a, PlayListView * lv) : QListViewItem (p), m_attr (a), listview (lv) {} + +KDE_NO_CDTOR_EXPORT +PlayListItem::PlayListItem (PlayListView *v, const NodePtr &e, QListViewItem *b) + : QListViewItem (v, b), node (e), listview (v) {} + +KDE_NO_CDTOR_EXPORT void PlayListItem::paintCell (QPainter * p, const QColorGroup & cg, int column, int width, int align) { + if (node && node->state == Node::state_began) { + QColorGroup mycg (cg); + mycg.setColor (QColorGroup::Foreground, listview->activeColor ()); + mycg.setColor (QColorGroup::Text, listview->activeColor ()); + QListViewItem::paintCell (p, mycg, column, width, align); + } else + QListViewItem::paintCell (p, cg, column, width, align); +} + +KDE_NO_CDTOR_EXPORT void PlayListItem::paintBranches (QPainter * p, const QColorGroup &, int w, int, int h) { + p->fillRect (0, 0, w, h, listview->paletteBackgroundColor()); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT +RootPlayListItem::RootPlayListItem (int _id, PlayListView *v, const NodePtr & e, QListViewItem * before, int flgs) + : PlayListItem (v, e, before), + id (_id), + flags (flgs), + show_all_nodes (false), + have_dark_nodes (false) {} + +KDE_NO_CDTOR_EXPORT void RootPlayListItem::paintCell (QPainter * p, const QColorGroup & cg, int column, int width, int align) { + QColorGroup mycg (cg); + mycg.setColor (QColorGroup::Base, listview->topLevelWidget()->paletteBackgroundColor()); + mycg.setColor (QColorGroup::Highlight, mycg.base ()); + mycg.setColor (QColorGroup::Text, listview->topLevelWidget()->paletteForegroundColor()); + mycg.setColor (QColorGroup::HighlightedText, mycg.text ()); + QListViewItem::paintCell (p, mycg, column, width, align); + qDrawShadeRect (p, 0, 0, width -1, height () -1, mycg, !isOpen ()); +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT PlayListView::PlayListView (QWidget * parent, View * view, KActionCollection * ac) + : KListView (parent, "kde_kmplayer_playlist"), + m_view (view), + m_find_dialog (0L), + m_active_color (30, 0, 255), + last_id (0), + last_drag_tree_id (0), + m_ignore_expanded (false) { + addColumn (QString ()); + header()->hide (); + //setRootIsDecorated (true); + setSorting (-1); + setAcceptDrops (true); + setDropVisualizer (true); + setItemsRenameable (true); + setItemMargin (2); + setPaletteBackgroundColor (QColor (0, 0, 0)); + setPaletteForegroundColor (QColor (0xB2, 0xB2, 0xB2)); + m_itemmenu = new QPopupMenu (this); + folder_pix = KGlobal::iconLoader ()->loadIcon (QString ("folder"), KIcon::Small); + auxiliary_pix = KGlobal::iconLoader ()->loadIcon (QString ("folder_grey"), KIcon::Small); + video_pix = KGlobal::iconLoader ()->loadIcon (QString ("video"), KIcon::Small); + info_pix = KGlobal::iconLoader ()->loadIcon (QString ("messagebox_info"), KIcon::Small); + img_pix = KGlobal::iconLoader ()->loadIcon (QString ("colorize"), KIcon::Small); + unknown_pix = KGlobal::iconLoader ()->loadIcon (QString ("unknown"), KIcon::Small); + menu_pix = KGlobal::iconLoader ()->loadIcon (QString ("player_playlist"), KIcon::Small); + config_pix = KGlobal::iconLoader ()->loadIcon (QString ("configure"), KIcon::Small); + url_pix = KGlobal::iconLoader ()->loadIcon (QString ("www"), KIcon::Small); + m_find = KStdAction::find (this, SLOT (slotFind ()), ac, "find"); + m_find_next = KStdAction::findNext (this, SLOT(slotFindNext()), ac, "next"); + m_find_next->setEnabled (false); + connect (this, SIGNAL (contextMenuRequested (QListViewItem *, const QPoint &, int)), this, SLOT (contextMenuItem (QListViewItem *, const QPoint &, int))); + connect (this, SIGNAL (expanded (QListViewItem *)), + this, SLOT (itemExpanded (QListViewItem *))); + connect (this, SIGNAL (dropped (QDropEvent *, QListViewItem *)), + this, SLOT (itemDropped (QDropEvent *, QListViewItem *))); + connect (this, SIGNAL (itemRenamed (QListViewItem *)), + this, SLOT (itemIsRenamed (QListViewItem *))); + connect (this, SIGNAL (selectionChanged (QListViewItem *)), + this, SLOT (itemIsSelected (QListViewItem *))); +} + +KDE_NO_CDTOR_EXPORT PlayListView::~PlayListView () { +} + +int PlayListView::addTree (NodePtr root, const QString & source, const QString & icon, int flags) { + //kdDebug () << "addTree " << source << " " << root->mrl()->src << endl; + RootPlayListItem * ritem = new RootPlayListItem (++last_id, this, root, lastChild(), flags); + ritem->source = source; + ritem->icon = icon; + ritem->setPixmap (0, !ritem->icon.isEmpty () + ? KGlobal::iconLoader ()->loadIcon (ritem->icon, KIcon::Small) + : url_pix); + updateTree (ritem, 0L, false); + return last_id; +} + +KDE_NO_EXPORT PlayListItem * PlayListView::populate +(NodePtr e, NodePtr focus, RootPlayListItem *root, PlayListItem * pitem, PlayListItem ** curitem) { + root->have_dark_nodes |= !e->expose (); + if (pitem && !root->show_all_nodes && !e->expose ()) { + for (NodePtr c = e->lastChild (); c; c = c->previousSibling ()) + populate (c, focus, root, pitem, curitem); + return pitem; + } + PlayListItem * item = pitem ? new PlayListItem (pitem, e, this) : root; + Mrl * mrl = e->mrl (); + QString text (e->nodeName()); + if (mrl && !root->show_all_nodes) { + if (mrl->pretty_name.isEmpty ()) { + if (!mrl->src.isEmpty()) + text = KURL(mrl->src).prettyURL (0, KURL::StripFileProtocol); + else if (e->isDocument ()) + text = e->hasChildNodes () ? i18n ("unnamed") : i18n ("none"); + } else + text = mrl->pretty_name; + } else if (e->id == id_node_text) + text = e->nodeValue (); + item->setText(0, text); + if (focus == e) + *curitem = item; + if (e->active ()) + ensureItemVisible (item); + for (NodePtr c = e->lastChild (); c; c = c->previousSibling ()) + populate (c, focus, root, item, curitem); + if (e->isElementNode ()) { + AttributePtr a = convertNode<Element> (e)->attributes ()->first (); + if (a) { + root->have_dark_nodes = true; + if (root->show_all_nodes) { + PlayListItem * as = new PlayListItem (item, e, this); + as->setText (0, i18n ("[attributes]")); + as->setPixmap (0, menu_pix); + for (; a; a = a->nextSibling ()) { + PlayListItem * ai = new PlayListItem (as, a, this); + ai->setText (0, QString ("%1=%2").arg ( + a->name ().toString ()).arg (a->value ())); + ai->setPixmap (0, config_pix); + } + } + } + } + if (item != root) { + Node::PlayType pt = e->playType (); + QPixmap * pix; + switch (pt) { + case Node::play_type_image: + pix = &img_pix; + break; + case Node::play_type_info: + pix = &info_pix; + break; + default: + if (pt > Node::play_type_none) + pix = &video_pix; + else + pix = item->firstChild () + ? e->auxiliaryNode () + ? &auxiliary_pix : &folder_pix + : &unknown_pix; + } + item->setPixmap (0, *pix); + if (root->flags & PlayListView::AllowDrag) + item->setDragEnabled (true); + } + return item; +} + +void PlayListView::updateTree (int id, NodePtr root, NodePtr active, + bool select, bool open) { + // TODO, if root is same as rootitems->node and treeversion is the same + // and show all nodes is unchanged then only update the cells + QWidget * w = focusWidget (); + if (w && w != this) + w->clearFocus (); + //setSelected (firstChild (), true); + RootPlayListItem * ritem = static_cast <RootPlayListItem *> (firstChild ()); + RootPlayListItem * before = 0L; + for (; ritem; ritem =static_cast<RootPlayListItem*>(ritem->nextSibling())) { + if (ritem->id == id) { + if (!root) + root = ritem->node; + break; // found based on id + } + if (id == -1) { // wildcard id + for (NodePtr n = root; n; n = n->parentNode ()) + if (n == ritem->node) { + root = n; + break; + } + if (root == ritem->node) { + id = ritem->id; + break; // found based on matching (ancestor) node + } + } + if (ritem->id < id) + before = ritem; + } + if (!root) { + delete ritem; + return; + } + if (!ritem) { + ritem =new RootPlayListItem(id, this, root, before,AllowDrops|TreeEdit); + ritem->setPixmap (0, url_pix); + } else + ritem->node = root; + m_find_next->setEnabled (!!m_current_find_elm); + bool need_timer = !tree_update; + tree_update = new TreeUpdate (ritem, active, select, open, tree_update); + if (need_timer) + QTimer::singleShot (0, this, SLOT (updateTrees ())); +} + +KDE_NO_EXPORT void PlayListView::updateTrees () { + for (; tree_update; tree_update = tree_update->next) { + updateTree (tree_update->root_item, tree_update->node, tree_update->select); + if (tree_update->open) // FIXME for non-root nodes lazy loading + setOpen (tree_update->root_item, true); + } +} + +void PlayListView::updateTree (RootPlayListItem * ritem, NodePtr active, bool select) { + bool set_open = ritem->id == 0 || (ritem ? ritem->isOpen () : false); + m_ignore_expanded = true; + PlayListItem * curitem = 0L; + while (ritem->firstChild ()) + delete ritem->firstChild (); + if (!ritem->node) + return; + populate (ritem->node, active, ritem, 0L, &curitem); + if (set_open && ritem->firstChild () && !ritem->isOpen ()) + setOpen (ritem, true); + if (curitem && select) { + setSelected (curitem, true); + ensureItemVisible (curitem); + } + if (!ritem->have_dark_nodes && ritem->show_all_nodes && !m_view->editMode()) + toggleShowAllNodes (); // redo, because the user can't change it anymore + m_ignore_expanded = false; +} + +void PlayListView::selectItem (const QString & txt) { + QListViewItem * item = selectedItem (); + if (item && item->text (0) == txt) + return; + item = findItem (txt, 0); + if (item) { + setSelected (item, true); + ensureItemVisible (item); + } +} + +KDE_NO_EXPORT QDragObject * PlayListView::dragObject () { + PlayListItem * item = static_cast <PlayListItem *> (selectedItem ()); + if (item && item->node) { + QString txt = item->node->isPlayable () + ? item->node->mrl ()->src : item->node->outerXML (); + QTextDrag * drag = new QTextDrag (txt, this); + last_drag_tree_id = rootItem (item)->id; + m_last_drag = item->node; + drag->setPixmap (*item->pixmap (0)); + if (!item->node->isPlayable ()) + drag->setSubtype ("xml"); + return drag; + } + return 0; +} + +KDE_NO_EXPORT void PlayListView::setFont (const QFont & fnt) { + setTreeStepSize (QFontMetrics (fnt).boundingRect ('m').width ()); + KListView::setFont (fnt); +} + +KDE_NO_EXPORT void PlayListView::contextMenuItem (QListViewItem * vi, const QPoint & p, int) { + if (vi) { + PlayListItem * item = static_cast <PlayListItem *> (vi); + if (item->node || item->m_attr) { + RootPlayListItem * ritem = rootItem (vi); + if (m_itemmenu->count () > 0) { + m_find->unplug (m_itemmenu); + m_find_next->unplug (m_itemmenu); + m_itemmenu->clear (); + } + m_itemmenu->insertItem (KGlobal::iconLoader ()->loadIconSet + (QString ("editcopy"), KIcon::Small, 0, true), + i18n ("&Copy to Clipboard"), + this, SLOT (copyToClipboard ()), 0, 0); + if (item->m_attr || + (item->node && (item->node->isPlayable () || + item->node->isDocument ()) && + item->node->mrl ()->bookmarkable)) + m_itemmenu->insertItem (KGlobal::iconLoader ()->loadIconSet + (QString ("bookmark_add"), KIcon::Small, 0, true), + i18n ("&Add Bookmark"), + this, SLOT (addBookMark ()), 0, 1); + if (ritem->have_dark_nodes) { + m_itemmenu->insertItem (i18n ("&Show all"), + this, SLOT (toggleShowAllNodes ()), 0, 2); + m_itemmenu->setItemChecked (2, ritem->show_all_nodes); + } + m_itemmenu->insertSeparator (); + m_find->plug (m_itemmenu); + m_find_next->plug (m_itemmenu); + emit prepareMenu (item, m_itemmenu); + m_itemmenu->exec (p); + } + } else + m_view->controlPanel ()->popupMenu ()->exec (p); +} + +void PlayListView::itemExpanded (QListViewItem * item) { + if (!m_ignore_expanded && item->childCount () == 1) { + PlayListItem * child_item = static_cast<PlayListItem*>(item->firstChild ()); + child_item->setOpen (rootItem (item)->show_all_nodes || + (child_item->node && child_item->node->expose ())); + } +} + +RootPlayListItem * PlayListView::rootItem (QListViewItem * item) const { + if (!item) + return 0L; + while (item->parent ()) + item = item->parent (); + return static_cast <RootPlayListItem *> (item); +} + +RootPlayListItem * PlayListView::rootItem (int id) const { + RootPlayListItem * ri = static_cast <RootPlayListItem *> (firstChild ()); + for (; ri; ri = static_cast <RootPlayListItem *> (ri->nextSibling ())) { + if (ri->id == id) + return ri; + } + return 0L; +} + +void PlayListView::copyToClipboard () { + PlayListItem * item = currentPlayListItem (); + QString text = item->text (0); + if (item->node) { + Mrl * mrl = item->node->mrl (); + if (mrl && !mrl->src.isEmpty ()) + text = mrl->src; + } + QApplication::clipboard()->setText (text); +} + +void PlayListView::addBookMark () { + PlayListItem * item = currentPlayListItem (); + if (item->node) { + Mrl * mrl = item->node->mrl (); + KURL url (mrl ? mrl->src : QString (item->node->nodeName ())); + emit addBookMark (mrl->pretty_name.isEmpty () ? url.prettyURL () : mrl->pretty_name, url.url ()); + } +} + +void PlayListView::toggleShowAllNodes () { + PlayListItem * cur_item = currentPlayListItem (); + if (cur_item) { + RootPlayListItem * ritem = rootItem (cur_item); + showAllNodes (rootItem (cur_item), !ritem->show_all_nodes); + } +} + +KDE_NO_EXPORT void PlayListView::showAllNodes(RootPlayListItem *ri, bool show) { + if (ri && ri->show_all_nodes != show) { + PlayListItem * cur_item = currentPlayListItem (); + ri->show_all_nodes = show; + updateTree (ri->id, ri->node, cur_item->node, true, false); + if (m_current_find_elm && + ri->node->document() == m_current_find_elm->document() && + !ri->show_all_nodes) { + if (!m_current_find_elm->expose ()) + m_current_find_elm = 0L; + m_current_find_attr = 0L; + } + } +} + +KDE_NO_EXPORT bool PlayListView::acceptDrag (QDropEvent * de) const { + QListViewItem * item = itemAt (contentsToViewport (de->pos ())); + if (item && (de->source () == this || isDragValid (de))) { + RootPlayListItem * ritem = rootItem (item); + return ritem->flags & AllowDrops; + } + return false; +} + +KDE_NO_EXPORT void PlayListView::itemDropped (QDropEvent * de, QListViewItem *after) { + if (!after) { // could still be a descendent + after = itemAt (contentsToViewport (de->pos ())); + if (after) + after = after->parent (); + } + if (after) { + RootPlayListItem * ritem = rootItem (after); + if (ritem->id > 0) + return; + NodePtr n = static_cast <PlayListItem *> (after)->node; + bool valid = n && (!n->isDocument () || n->hasChildNodes ()); + KURL::List sl; + if (KURLDrag::canDecode (de)) { + KURLDrag::decode (de, sl); + } else if (QTextDrag::canDecode (de)) { + QString text; + QTextDrag::decode (de, text); + sl.push_back (KURL (text)); + } + if (valid && sl.size () > 0) { + bool as_child = n->isDocument () || n->hasChildNodes (); + NodePtr d = n->document (); + for (int i = sl.size (); i > 0; i--) { + Node * ni = new KMPlayer::GenericURL (d, sl[i-1].url ()); + if (as_child) + n->insertBefore (ni, n->firstChild ()); + else + n->parentNode ()->insertBefore (ni, n->nextSibling ()); + } + PlayListItem * citem = currentPlayListItem (); + NodePtr cn; + if (citem) + cn = citem->node; + updateTree (ritem, cn, true); + } + } else + m_view->dropEvent (de); +} + +KDE_NO_EXPORT void PlayListView::itemIsRenamed (QListViewItem * qitem) { + PlayListItem * item = static_cast <PlayListItem *> (qitem); + if (item->node) { + RootPlayListItem * ri = rootItem (qitem); + if (!ri->show_all_nodes && item->node->isEditable ()) { + item->node->setNodeName (item->text (0)); + if (item->node->mrl ()->pretty_name.isEmpty ()) + item->setText (0, KURL (item->node->mrl ()->src).prettyURL (0, KURL::StripFileProtocol)); + } else // restore damage .. + updateTree (ri, item->node, true); + } else if (item->m_attr) { + QString txt = item->text (0); + int pos = txt.find (QChar ('=')); + if (pos > -1) { + item->m_attr->setName (txt.left (pos)); + item->m_attr->setValue (txt.mid (pos + 1)); + } else { + item->m_attr->setName (txt); + item->m_attr->setValue (QString ("")); + } + PlayListItem * pi = static_cast <PlayListItem *> (item->parent ()); + if (pi && pi->node) + pi->node->document ()->m_tree_version++; + } +} + +KDE_NO_EXPORT void PlayListView::itemIsSelected (QListViewItem * qitem) { + RootPlayListItem * ri = rootItem (qitem); + setItemsRenameable (ri && (ri->flags & TreeEdit) && ri != qitem); +} + +KDE_NO_EXPORT void PlayListView::rename (QListViewItem * qitem, int c) { + PlayListItem * item = static_cast <PlayListItem *> (qitem); + if (rootItem (qitem)->show_all_nodes && item && item->m_attr) { + PlayListItem * pi = static_cast <PlayListItem *> (qitem->parent ()); + if (pi && pi->node && pi->node->isEditable ()) + KListView::rename (item, c); + } else if (item && item->node && item->node->isEditable ()) { + if (!rootItem (qitem)->show_all_nodes && + item->node->isPlayable () && + item->node->mrl ()->pretty_name.isEmpty ()) + // populate() has crippled src, restore for editing + item->setText (0, item->node->mrl ()->src); + KListView::rename (item, c); + } +} + +KDE_NO_EXPORT void PlayListView::editCurrent () { + QListViewItem * qitem = selectedItem (); + if (qitem) { + RootPlayListItem * ri = rootItem (qitem); + if (ri && (ri->flags & TreeEdit) && ri != qitem) + rename (qitem, 0); + } +} + +KDE_NO_EXPORT void PlayListView::slotFind () { + m_current_find_elm = 0L; + if (!m_find_dialog) { + m_find_dialog = new KFindDialog (false, this, "kde_kmplayer_find", KFindDialog::CaseSensitive); + m_find_dialog->setHasSelection (false); + connect(m_find_dialog, SIGNAL(okClicked ()), this, SLOT(slotFindOk ())); + } else + m_find_dialog->setPattern (QString ()); + m_find_dialog->show (); +} + +static QListViewItem * findNodeInTree (NodePtr n, QListViewItem * item) { + //kdDebug () << "item:" << item->text (0) << " n:" << (n ? n->nodeName () : "null" ) <<endl; + PlayListItem * pi = static_cast <PlayListItem *> (item); + if (!n || !pi->node) + return 0L; + if (n == pi->node) + return item; + for (QListViewItem * ci = item->firstChild(); ci; ci = ci->nextSibling ()) { + //kdDebug () << "ci:" << ci->text (0) << " n:" << n->nodeName () <<endl; + QListViewItem * vi = findNodeInTree (n, ci); + if (vi) + return vi; + } + return 0L; + +} + +KDE_NO_EXPORT void PlayListView::slotFindOk () { + if (!m_find_dialog) + return; + m_find_dialog->hide (); + long opt = m_find_dialog->options (); + current_find_tree_id = 0; + if (opt & KFindDialog::FromCursor && currentItem ()) { + PlayListItem * lvi = currentPlayListItem (); + if (lvi && lvi->node) { + m_current_find_elm = lvi->node; + current_find_tree_id = rootItem (lvi)->id; + } else if (lvi && lvi->m_attr) { + PlayListItem*pi=static_cast<PlayListItem*>(currentItem()->parent()); + if (pi) { + m_current_find_attr = lvi->m_attr; + m_current_find_elm = pi->node; + } + } + } else if (!(opt & KFindDialog::FindIncremental)) + m_current_find_elm = 0L; + if (!m_current_find_elm) { + PlayListItem * lvi = static_cast <PlayListItem *> (firstChild ()); + if (lvi) + m_current_find_elm = lvi->node; + } + if (m_current_find_elm) + slotFindNext (); +} + +/* A bit tricky, but between the find's PlayListItems might be gone, so + * try to match on the generated tree following the source's document tree + */ +KDE_NO_EXPORT void PlayListView::slotFindNext () { + if (!m_find_dialog) + return; + QString str = m_find_dialog->pattern(); + if (!m_current_find_elm || str.isEmpty ()) + return; + long opt = m_find_dialog->options (); + QRegExp regexp; + if (opt & KFindDialog::RegularExpression) + regexp = str; + bool cs = (opt & KFindDialog::CaseSensitive); + bool found = false; + NodePtr node, n = m_current_find_elm; + RootPlayListItem * ri = rootItem (current_find_tree_id); + while (!found && n) { + if (ri->show_all_nodes || n->expose ()) { + bool elm = n->isElementNode (); + QString val = n->nodeName (); + if (elm && !ri->show_all_nodes) { + Mrl * mrl = n->mrl (); + if (mrl) { + if (mrl->pretty_name.isEmpty ()) { + if (!mrl->src.isEmpty()) + val = KURL(mrl->src).prettyURL(); + } else + val = mrl->pretty_name; + } + } else if (!elm) + val = n->nodeValue (); + if (((opt & KFindDialog::RegularExpression) && + val.find (regexp, 0) > -1) || + (!(opt & KFindDialog::RegularExpression) && + val.find (str, 0, cs) > -1)) { + node = n; + m_current_find_attr = 0L; + found = true; + } else if (elm && ri->show_all_nodes) { + for (AttributePtr a = convertNode <Element> (n)->attributes ()->first (); a; a = a->nextSibling ()) { + QString attr = a->name ().toString (); + if (((opt & KFindDialog::RegularExpression) && + (attr.find (regexp, 0) || a->value ().find (regexp, 0) > -1)) || + (!(opt & KFindDialog::RegularExpression) && + (attr.find (str, 0, cs) > -1 || a->value ().find (str, 0, cs) > -1))) { + node = n; + m_current_find_attr = a; + found = true; + break; + } + } + } + } + if (n) { //set pointer to next + if (opt & KFindDialog::FindBackwards) { + if (n->lastChild ()) { + n = n->lastChild (); + } else if (n->previousSibling ()) { + n = n->previousSibling (); + } else { + for (n = n->parentNode (); n; n = n->parentNode ()) + if (n->previousSibling ()) { + n = n->previousSibling (); + break; + } + while (!n && current_find_tree_id > 0) { + ri = rootItem (--current_find_tree_id); + if (ri) + n = ri->node; + } + } + } else { + if (n->firstChild ()) { + n = n->firstChild (); + } else if (n->nextSibling ()) { + n = n->nextSibling (); + } else { + for (n = n->parentNode (); n; n = n->parentNode ()) + if (n->nextSibling ()) { + n = n->nextSibling (); + break; + } + while (!n) { + ri = rootItem (++current_find_tree_id); + if (!ri) + break; + n = ri->node; + } + } + } + } + } + m_current_find_elm = n; + kdDebug () << " search for " << str << "=" << (node ? node->nodeName () : "not found") << " next:" << (n ? n->nodeName () : " not found") << endl; + if (found) { + QListViewItem * fc = findNodeInTree (node, ri); + if (!fc) { + m_current_find_elm = 0L; + kdDebug () << "node not found in tree tree:" << ri->id << endl; + } else { + setSelected (fc, true); + if (m_current_find_attr && fc->firstChild () && fc->firstChild ()->firstChild ()) + ensureItemVisible (fc->firstChild ()->firstChild ()); + ensureItemVisible (fc); + } + } + m_find_next->setEnabled (!!m_current_find_elm); +} + +#include "playlistview.moc" diff --git a/src/playlistview.h b/src/playlistview.h new file mode 100644 index 0000000..c7dbcd8 --- /dev/null +++ b/src/playlistview.h @@ -0,0 +1,174 @@ +/** + * Copyright (C) 2006 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef PLAYLISTVIEW_H +#define PLAYLISTVIEW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <klistview.h> + +#include "kmplayerplaylist.h" + +class QFont; +class QPixmap; +class QPainter; +class QPopupMenu; +class QDropEvent; + +namespace KMPlayer { + +class View; +class PlayListView; + +bool isDragValid (QDropEvent * de) KMPLAYER_NO_MBR_EXPORT; + +/* + * An item in the playlist + */ +class KMPLAYER_NO_EXPORT PlayListItem : public QListViewItem { +public: + PlayListItem (QListViewItem *p, const NodePtr & e, PlayListView * lv); + PlayListItem (QListViewItem *p, const AttributePtr & e, PlayListView * lv); + PlayListItem (PlayListView *v, const NodePtr & d, QListViewItem * b); + KDE_NO_CDTOR_EXPORT ~PlayListItem () {} + void paintCell (QPainter * p, const QColorGroup & cg, int column, int width, int align); + void paintBranches(QPainter *p, const QColorGroup &cg, int w, int y, int h); + PlayListView * playListView () const; + NodePtrW node; + AttributePtrW m_attr; + PlayListView * listview; +protected: + PlayListItem (PlayListView *v, const NodePtr & e); +}; + +class KMPLAYER_NO_EXPORT RootPlayListItem : public PlayListItem { +public: + RootPlayListItem (int id, PlayListView *v, const NodePtr & d, QListViewItem * b, int flags); + KDE_NO_CDTOR_EXPORT ~RootPlayListItem () {} + void paintCell (QPainter * p, const QColorGroup & cg, int column, int width, int align); + QString source; + QString icon; + int id; + int flags; + bool show_all_nodes; + bool have_dark_nodes; +}; + +/* + * The playlist GUI + */ +class KMPLAYER_EXPORT PlayListView : public KListView { + Q_OBJECT +public: + enum Flags { + AllowDrops = 0x01, AllowDrag = 0x02, + InPlaceEdit = 0x04, TreeEdit = 0x08, + Moveable = 0x10, Deleteable = 0x20 + }; + PlayListView (QWidget * parent, View * view, KActionCollection * ac); + ~PlayListView (); + void selectItem (const QString & txt); + void showAllNodes (RootPlayListItem *, bool show=true); + void setActiveForegroundColor (const QColor & c) { m_active_color = c; } + const QColor & activeColor () const { return m_active_color; } + int addTree (NodePtr r, const QString & src, const QString & ico, int flgs); + RootPlayListItem * rootItem (QListViewItem * item) const; + RootPlayListItem * rootItem (int id) const; + void setFont (const QFont &); + PlayListItem * currentPlayListItem () const; + PlayListItem * selectedPlayListItem () const; + NodePtr lastDragNode () const { return m_last_drag; } + int lastDragTreeId () const { return last_drag_tree_id; } +signals: + void addBookMark (const QString & title, const QString & url); + void prepareMenu (KMPlayer::PlayListItem * item, QPopupMenu * menu); +protected: + bool acceptDrag (QDropEvent* event) const; + QDragObject * dragObject (); +public slots: + void editCurrent (); + void rename (QListViewItem * item, int c); + void updateTree (int id, NodePtr root, NodePtr active, bool sel, bool open); +private slots: + void contextMenuItem (QListViewItem *, const QPoint &, int); + void itemExpanded (QListViewItem *); + void copyToClipboard (); + void addBookMark (); + void toggleShowAllNodes (); + void itemDropped (QDropEvent * e, QListViewItem * after); + void itemIsRenamed (QListViewItem * item); + void itemIsSelected (QListViewItem * item); + void updateTrees (); + void slotFind (); + void slotFindOk (); + void slotFindNext (); +private: + void updateTree (RootPlayListItem * ritem, NodePtr active, bool select); + PlayListItem * populate (NodePtr e, NodePtr focus, RootPlayListItem *root, PlayListItem * item, PlayListItem ** curitem); + struct KMPLAYER_NO_EXPORT TreeUpdate { + KDE_NO_CDTOR_EXPORT TreeUpdate (RootPlayListItem *ri, NodePtr n, bool s, bool o, SharedPtr <TreeUpdate> &nx) : root_item (ri), node (n), select (s), open (o), next (nx) {} + KDE_NO_CDTOR_EXPORT ~TreeUpdate () {} + RootPlayListItem * root_item; + NodePtrW node; + bool select; + bool open; + SharedPtr <TreeUpdate> next; + }; + SharedPtr <TreeUpdate> tree_update; + View * m_view; + QPopupMenu * m_itemmenu; + KAction * m_find; + KAction * m_find_next; + KFindDialog * m_find_dialog; + QPixmap folder_pix; + QPixmap auxiliary_pix; + QPixmap video_pix; + QPixmap unknown_pix; + QPixmap menu_pix; + QPixmap config_pix; + QPixmap url_pix; + QPixmap info_pix; + QPixmap img_pix; + QColor m_active_color; + NodePtrW m_current_find_elm; + NodePtrW m_last_drag; + AttributePtrW m_current_find_attr; + int last_id; + int last_drag_tree_id; + int current_find_tree_id; + bool m_ignore_expanded; +}; + +KDE_NO_EXPORT inline PlayListView * PlayListItem::playListView () const { + return static_cast <PlayListView *> (listView ()); +} + +KDE_NO_EXPORT inline PlayListItem * PlayListView::currentPlayListItem () const { + return static_cast <PlayListItem *> (currentItem ()); +} + +KDE_NO_EXPORT inline PlayListItem * PlayListView::selectedPlayListItem() const { + return static_cast <PlayListItem *> (selectedItem ()); +} + +} // namespace + +#endif // PLAYLISTVIEW_H diff --git a/src/pluginsinfo b/src/pluginsinfo new file mode 100644 index 0000000..0cc3d74 --- /dev/null +++ b/src/pluginsinfo @@ -0,0 +1,31 @@ +number=5 + +[0] +description=RealPlayer LiveConnect-Enabled Plug-In G2 +file=libkmplayerpart.so +mime=audio/x-pn-realaudio:rm:Real Audio Stream;audio/x-pn-realaudio-plugin:rpm,rm,ram:RealPlayer Plug-in +name=RealPlayer + +[1] +description=Windows Media Player Plug-in +file=libkmplayerpart.so +mime=application/x-mplayer2:wmp:Windows Media Player;audio/x-ms-wma:wma:Windows Media Audio;video/x-ms-asf:asx,asf:Media Files;video/x-ms-asf-plugin:*:Media Files;video/x-ms-wmv:wmv:Windows Media Video;video/msvideo:avi,*:AVI;video/x-ms-wmp:wmp,*:Windows Media;video/x-ms-wvx:wvx,*:Windows Media;audio/x-ms-wax:wax,*:Windows Media;application/x-drm-v2:asx,*:Windows Media;audio/wav:wav,*:Microsoft wave file;audio/x-wav:wav,*:Microsoft wave file;video/x-ms-wm:wm,*:Media Files +name=Windows Media Player Plugin + +[2] +description=QuickTime Movie +file=libkmplayerpart.so +mime=video/quicktime:mov,qt:QuickTime +name=QuickTime Plug-in + +[3] +description=Shockwave Flash 9.0 r64 +file=libkmplayerpart.so +mime=application/x-shockwave-flash:swf:Shockwave Flash +name=Shockwave Flash + +[4] +description=FutureSplash Player 9.0 r64 +file=libkmplayerpart.so +mime=application/futuresplash:spl:FutureSplash Player +name=FutureSplash Player diff --git a/src/pref.cpp b/src/pref.cpp new file mode 100644 index 0000000..ff39751 --- /dev/null +++ b/src/pref.cpp @@ -0,0 +1,866 @@ +/** + * Copyright (C) 2003 Joonas Koivunen <[email protected]> + * Copyright (C) 2003 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef Always + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <qlayout.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qstringlist.h> +#include <qcombobox.h> +#include <qlineedit.h> +#include <qgroupbox.h> +#include <qwhatsthis.h> +#include <qtabwidget.h> +#include <qslider.h> +#include <qbuttongroup.h> +#include <qspinbox.h> +#include <qmessagebox.h> +#include <qmap.h> +#include <qtimer.h> +#include <qfont.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <klineedit.h> +#include <kiconloader.h> +#include <kdeversion.h> +#include <kcombobox.h> +#include <kcolorbutton.h> +#include <kurlrequester.h> +#include <kfontdialog.h> + +#include "pref.h" +#include "kmplayerpartbase.h" +#include "kmplayerprocess.h" +#include "kmplayerconfig.h" + + +using namespace KMPlayer; + +KDE_NO_CDTOR_EXPORT Preferences::Preferences(PartBase * player, Settings * settings) +: KDialogBase (IconList, i18n ("Preferences"), + Help|Default|Ok|Apply|Cancel, Ok, player->view (), 0, false) +{ + QFrame *frame; + QTabWidget * tab; + QStringList hierarchy; // typo? :) + QVBoxLayout *vlay; + + frame = addPage(i18n("General Options"), QString(), KGlobal::iconLoader()->loadIcon (QString ("kmplayer"), KIcon::NoGroup, 32)); + vlay = new QVBoxLayout(frame, marginHint(), spacingHint()); + tab = new QTabWidget (frame); + vlay->addWidget (tab); + m_GeneralPageGeneral = new PrefGeneralPageGeneral (tab, settings); + tab->insertTab (m_GeneralPageGeneral, i18n("General")); + m_GeneralPageLooks = new PrefGeneralPageLooks (tab, settings); + tab->insertTab (m_GeneralPageLooks, i18n("Looks")); + m_GeneralPageOutput = new PrefGeneralPageOutput + (tab, settings->audiodrivers, settings->videodrivers); + tab->insertTab (m_GeneralPageOutput, i18n("Output")); + entries.insert (i18n("General Options"), tab); + + frame = addPage (i18n ("Source"), QString(), KGlobal::iconLoader()->loadIcon (QString ("source"), KIcon::NoGroup, 32)); + vlay = new QVBoxLayout (frame, marginHint(), spacingHint()); + tab = new QTabWidget (frame); + vlay->addWidget (tab); + m_SourcePageURL = new PrefSourcePageURL (tab); + tab->insertTab (m_SourcePageURL, i18n ("URL")); + entries.insert (i18n("Source"), tab); + + frame = addPage (i18n ("Recording"), QString(), KGlobal::iconLoader()->loadIcon (QString ("video"), KIcon::NoGroup, 32)); + vlay = new QVBoxLayout (frame, marginHint(), spacingHint()); + tab = new QTabWidget (frame); + vlay->addWidget (tab); + + int recorders_count = 3; + m_MEncoderPage = new PrefMEncoderPage (tab, player); + tab->insertTab (m_MEncoderPage, i18n ("MEncoder")); + recorders = m_MEncoderPage; + + m_FFMpegPage = new PrefFFMpegPage (tab, player); + tab->insertTab (m_FFMpegPage, i18n ("FFMpeg")); + m_MEncoderPage->next = m_FFMpegPage; + + m_MPlayerDumpstreamPage = new PrefMPlayerDumpstreamPage (tab, player); + // tab->insertTab (m_MPlayerDumpstreamPage, i18n ("MPlayer -dumpstream")); + m_FFMpegPage->next = m_MPlayerDumpstreamPage; +#ifdef HAVE_XINE + recorders_count = 4; + m_XinePage = new PrefXinePage (tab, player); + // tab->insertTab (m_XinePage, i18n ("Xine")); + m_MPlayerDumpstreamPage->next = m_XinePage; +#endif + m_RecordPage = new PrefRecordPage (tab, player, recorders, recorders_count); + tab->insertTab (m_RecordPage, i18n ("General"), 0); + tab->setCurrentPage (0); + entries.insert (i18n("Recording"), tab); + + frame = addPage (i18n ("Output Plugins"), QString(), KGlobal::iconLoader()->loadIcon (QString ("image"), KIcon::NoGroup, 32)); + vlay = new QVBoxLayout(frame, marginHint(), spacingHint()); + tab = new QTabWidget (frame); + vlay->addWidget (tab); + m_OPPagePostproc = new PrefOPPagePostProc (tab); + tab->insertTab (m_OPPagePostproc, i18n ("Postprocessing")); + entries.insert (i18n("Postprocessing"), tab); + + for (PreferencesPage * p = settings->pagelist; p; p = p->next) + addPrefPage (p); + + + connect (this, SIGNAL (defaultClicked ()), SLOT (confirmDefaults ())); +} + +KDE_NO_EXPORT void Preferences::setPage (const char * name) { + QObject * o = child (name, "QFrame"); + if (!o) return; + QFrame * page = static_cast <QFrame *> (o); + QWidget * w = page->parentWidget (); + while (w && !w->inherits ("QTabWidget")) + w = w->parentWidget (); + if (!w) return; + QTabWidget * t = static_cast <QTabWidget*> (w); + t->setCurrentPage (t->indexOf(page)); + if (!t->parentWidget() || !t->parentWidget()->inherits ("QFrame")) + return; + showPage (pageIndex (t->parentWidget ())); +} + +KDE_NO_EXPORT void Preferences::addPrefPage (PreferencesPage * page) { + QString item, subitem, icon; + QFrame * frame; + QTabWidget * tab; + QVBoxLayout *vlay; + page->prefLocation (item, icon, subitem); + if (item.isEmpty ()) + return; + QMap<QString, QTabWidget *>::iterator en_it = entries.find (item); + if (en_it == entries.end ()) { + frame = addPage (item, QString(), KGlobal::iconLoader()->loadIcon ((icon), KIcon::NoGroup, 32)); + vlay = new QVBoxLayout (frame, marginHint(), spacingHint()); + tab = new QTabWidget (frame); + vlay->addWidget (tab); + entries.insert (item, tab); + } else + tab = en_it.data (); + frame = page->prefPage (tab); + tab->insertTab (frame, subitem); +} + +KDE_NO_EXPORT void Preferences::removePrefPage(PreferencesPage * page) { + QString item, subitem, icon; + page->prefLocation (item, icon, subitem); + if (item.isEmpty ()) + return; + QMap<QString, QTabWidget *>::iterator en_it = entries.find (item); + if (en_it == entries.end ()) + return; + QTabWidget * tab = en_it.data (); + for (int i = 0; i < tab->count (); i++) + if (tab->label (i) == subitem) { + QWidget * w = tab->page (i); + tab->removePage (w); + delete w; + break; + } + if (!tab->count ()) { + QWidget * w = tab->parentWidget (); + while (w && !w->inherits ("QFrame")) + w = w->parentWidget (); + delete w; + entries.erase (en_it); + } +} + +KDE_NO_CDTOR_EXPORT Preferences::~Preferences() { +} + +KDE_NO_CDTOR_EXPORT PrefGeneralPageGeneral::PrefGeneralPageGeneral(QWidget *parent, Settings *) +: QFrame (parent, "GeneralPage") +{ + QVBoxLayout *layout = new QVBoxLayout(this, 5, 2); + + QGroupBox *windowbox = new QGroupBox(1, Qt::Vertical, i18n("Window"), this); + QWidget * wbox = new QWidget (windowbox); + QWidget * bbox = new QWidget (wbox); + QGridLayout * gridlayout = new QGridLayout (bbox, 2, 2); + keepSizeRatio = new QCheckBox (i18n ("Keep size ratio"), bbox, 0); + QWhatsThis::add(keepSizeRatio, i18n("When checked, movie will keep its aspect ratio\nwhen window is resized")); + dockSysTray = new QCheckBox (i18n ("Dock in system tray"), bbox, 0); + QWhatsThis::add (dockSysTray, i18n ("When checked, an icon of KMPlayer will be added to the system tray.\nWhen clicked it will hide KMPlayer's main window and removing KMPlayer's taskbar button.")); + autoResize = new QCheckBox (i18n ("Auto resize to video sizes"), bbox); + QWhatsThis::add (autoResize, i18n("When checked, KMPlayer will resize to movie sizes\nwhen video starts")); + gridlayout->addWidget (keepSizeRatio, 0, 0); + gridlayout->addWidget (dockSysTray, 1, 0); + gridlayout->addWidget (autoResize, 0, 1); + sizesChoice = new QButtonGroup (2, Qt::Vertical, wbox); + new QRadioButton (i18n("Remember window size on exit"), sizesChoice); + new QRadioButton (i18n("Always start with fixed size"), sizesChoice); + QVBoxLayout * vbox = new QVBoxLayout (wbox, 2, 2); + vbox->addWidget (bbox); + vbox->addWidget (sizesChoice); + + QGroupBox *playbox =new QGroupBox(4, Qt::Vertical,i18n("Playing"),this); + loop = new QCheckBox (i18n("Loop"), playbox); + QWhatsThis::add(loop, i18n("Makes current movie loop")); + framedrop = new QCheckBox (i18n ("Allow framedrops"), playbox); + QWhatsThis::add (framedrop, i18n ("Allow dropping frames for better audio and video synchronization")); + adjustvolume = new QCheckBox(i18n("Auto set volume on start"), playbox); + QWhatsThis::add (adjustvolume, i18n ("When a new source is selected, the volume will be set according the volume control")); + adjustcolors = new QCheckBox(i18n("Auto set colors on start"), playbox); + QWhatsThis::add (adjustcolors, i18n ("When a movie starts, the colors will be set according the sliders for colors")); + + QGroupBox * gbox =new QGroupBox (1, Qt::Vertical, i18n("Control Panel"), this); + bbox =new QWidget (gbox); + //QGroupBox * bbox = gbox; + gridlayout = new QGridLayout (bbox, 3, 2); + showConfigButton = new QCheckBox(i18n("Show config button"), bbox); + QWhatsThis::add (showConfigButton, i18n ("Add a button that will popup a config menu")); + showPlaylistButton = new QCheckBox(i18n("Show playlist button"), bbox); + QWhatsThis::add (showPlaylistButton, i18n ("Add a playlist button to the control buttons")); + showRecordButton = new QCheckBox(i18n("Show record button"), bbox); + QWhatsThis::add (showRecordButton, i18n ("Add a record button to the control buttons")); + showBroadcastButton = new QCheckBox (i18n ("Show broadcast button"), bbox); + QWhatsThis::add (showBroadcastButton, i18n ("Add a broadcast button to the control buttons")); + gridlayout->addWidget (showConfigButton, 0, 0); + gridlayout->addWidget (showPlaylistButton, 0, 1); + gridlayout->addWidget (showRecordButton, 1, 0); + gridlayout->addWidget (showBroadcastButton, 1, 1); + //QWidget *seekingWidget = new QWidget (bbox); + QHBoxLayout *seekLayout = new QHBoxLayout (bbox); + seekLayout->addWidget(new QLabel(i18n("Forward/backward seek time:"),bbox)); + seekLayout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Minimum)); + seekTime = new QSpinBox(1, 600, 1, bbox); + seekLayout->addWidget(seekTime); + seekLayout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Minimum)); + gridlayout->addMultiCellLayout (seekLayout, 2, 2, 0, 1); + + layout->addWidget (windowbox); + layout->addWidget (playbox); + layout->addWidget (gbox); + //layout->addWidget(autoHideSlider); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +KDE_NO_CDTOR_EXPORT PrefGeneralPageLooks::PrefGeneralPageLooks (QWidget *parent, Settings * settings) + : QFrame (parent, "LooksPage"), + colors (settings->colors), + fonts (settings->fonts) { + QVBoxLayout *layout = new QVBoxLayout(this, 5, 2); + + QGroupBox *colorbox= new QGroupBox(2, Qt::Horizontal, i18n("Colors"), this); + colorscombo = new QComboBox (colorbox); + for (int i = 0; i < int (ColorSetting::last_target); i++) + colorscombo->insertItem (colors[i].title); + colorscombo->setCurrentItem (0); + connect (colorscombo, SIGNAL (activated (int)), + this, SLOT (colorItemChanged(int))); + colorbutton = new KColorButton (colorbox); + colorbutton->setColor (colors[0].color); + connect (colorbutton, SIGNAL (changed (const QColor &)), + this, SLOT (colorCanged (const QColor &))); + + QGroupBox *fontbox = new QGroupBox (2,Qt::Horizontal, i18n ("Fonts"), this); + fontscombo = new QComboBox (fontbox); + for (int i = 0; i < int (FontSetting::last_target); i++) + fontscombo->insertItem (fonts[i].title); + fontscombo->setCurrentItem (0); + connect (fontscombo, SIGNAL (activated (int)), + this, SLOT (fontItemChanged(int))); + fontbutton = new QPushButton (i18n ("AaBbCc"), fontbox); + fontbutton->setFlat (true); + fontbutton->setFont (fonts[0].font); + connect (fontbutton, SIGNAL (clicked ()), this, SLOT (fontClicked ())); + + layout->addWidget (colorbox); + layout->addWidget (fontbox); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +KDE_NO_EXPORT void PrefGeneralPageLooks::colorItemChanged (int c) { + if (c < int (ColorSetting::last_target)) + colorbutton->setColor (colors[c].newcolor); +} + +KDE_NO_EXPORT void PrefGeneralPageLooks::colorCanged (const QColor & c) { + if (colorscombo->currentItem () < int (ColorSetting::last_target)) + colors[colorscombo->currentItem ()].newcolor = c; +} + +KDE_NO_EXPORT void PrefGeneralPageLooks::fontItemChanged (int f) { + if (f < int (FontSetting::last_target)) + fontbutton->setFont (fonts[f].newfont); +} + +KDE_NO_EXPORT void PrefGeneralPageLooks::fontClicked () { + if (fontscombo->currentItem () < int (FontSetting::last_target)) { + QFont myfont = fonts [fontscombo->currentItem ()].newfont; + int res = KFontDialog::getFont (myfont, false, this); + if (res == KFontDialog::Accepted) { + fonts [fontscombo->currentItem ()].newfont = myfont; + fontbutton->setFont (myfont); + } + } +} + +KDE_NO_CDTOR_EXPORT PrefSourcePageURL::PrefSourcePageURL (QWidget *parent) +: QFrame (parent, "URLPage") +{ + QVBoxLayout *layout = new QVBoxLayout (this, 5, 5); + QHBoxLayout * urllayout = new QHBoxLayout (); + QHBoxLayout * sub_urllayout = new QHBoxLayout (); + QLabel *urlLabel = new QLabel (i18n ("Location:"), this, 0); + urllist = new KComboBox (true, this); + urllist->setMaxCount (20); + urllist->setDuplicatesEnabled (false); // not that it helps much :( + url = new KURLRequester (urllist, this); + QWhatsThis::add (url, i18n ("Location of the playable item")); + //url->setShowLocalProtocol (true); + url->setSizePolicy (QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred)); + QLabel *sub_urlLabel = new QLabel (i18n ("Sub title:"), this, 0); + sub_urllist = new KComboBox (true, this); + sub_urllist->setMaxCount (20); + sub_urllist->setDuplicatesEnabled (false); // not that it helps much :( + sub_url = new KURLRequester (sub_urllist, this); + QWhatsThis::add (sub_url, i18n ("Optional location of a file containing the subtitles of the URL above")); + sub_url->setSizePolicy (QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred)); + backend = new QListBox (this); + allowhref = new QCheckBox (i18n ("Enable 'Click to Play' support"), this); + QWhatsThis::add (allowhref, i18n ("Support for WEB pages having a start image")); + layout->addWidget (allowhref); + urllayout->addWidget (urlLabel); + urllayout->addWidget (url); + layout->addLayout (urllayout); + sub_urllayout->addWidget (sub_urlLabel); + sub_urllayout->addWidget (sub_url); + layout->addLayout (sub_urllayout); + layout->addItem (new QSpacerItem (0, 10, QSizePolicy::Minimum, QSizePolicy::Minimum)); + QGridLayout * gridlayout = new QGridLayout (2, 2); + QLabel *backendLabel = new QLabel (i18n ("Use movie player:"), this, 0); + //QWhatsThis::add (allowhref, i18n ("Explain this in a few lines")); + gridlayout->addWidget (backendLabel, 0, 0); + gridlayout->addWidget (backend, 1, 0); + gridlayout->addMultiCell (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 1, 1, 1); + QGroupBox *cbox = new QGroupBox(1, Qt::Vertical, i18n("Network bandwidth"), this); + QWidget * wbox = new QWidget (cbox); + QGridLayout * bitratelayout = new QGridLayout (wbox, 2, 3, 5); + prefBitRate = new QLineEdit (wbox); + QWhatsThis::add (prefBitRate, i18n("Sometimes it is possible to choose between various streams given a particular bitrate.\nThis option sets how much bandwidth you would prefer to allocate to video.")); + maxBitRate = new QLineEdit (wbox); + QWhatsThis::add (maxBitRate, i18n("Sometimes it is possible to choose between various streams given a particular bitrate.\nThis option sets the maximum bandwidth you have available for video.")); + bitratelayout->addWidget(new QLabel(i18n("Preferred bitrate:"), wbox), 0, 0); + bitratelayout->addWidget (prefBitRate, 0, 1); + bitratelayout->addWidget (new QLabel (i18n ("kbit/s"), wbox), 0, 2); + bitratelayout->addWidget (new QLabel(i18n("Maximum bitrate:"), wbox), 1, 0); + bitratelayout->addWidget (maxBitRate, 1, 1); + bitratelayout->addWidget (new QLabel (i18n ("kbit/s"), wbox), 1, 2); + layout->addLayout (gridlayout); + layout->addWidget (cbox); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + connect (urllist, SIGNAL(textChanged (const QString &)), + this, SLOT (slotTextChanged (const QString &))); + connect (sub_urllist, SIGNAL(textChanged (const QString &)), + this, SLOT (slotTextChanged (const QString &))); +} + +KDE_NO_EXPORT void PrefSourcePageURL::slotBrowse () { +} + +KDE_NO_EXPORT void PrefSourcePageURL::slotTextChanged (const QString &) { + changed = true; +} + +KDE_NO_CDTOR_EXPORT PrefRecordPage::PrefRecordPage (QWidget *parent, PartBase * player, RecorderPage * rl, int rec_len) : QFrame (parent, "RecordPage"), m_player (player), m_recorders (rl), m_recorders_length (rec_len) { + QVBoxLayout *layout = new QVBoxLayout (this, 5, 5); + QHBoxLayout * urllayout = new QHBoxLayout (); + QLabel *urlLabel = new QLabel (i18n ("Output file:"), this); + url = new KURLRequester ("", this); + url->setShowLocalProtocol (true); + urllayout->addWidget (urlLabel); + urllayout->addWidget (url); + recordButton = new QPushButton (i18n ("Start &Recording"), this); + connect (recordButton, SIGNAL (clicked ()), this, SLOT (slotRecord ())); + QHBoxLayout *buttonlayout = new QHBoxLayout; + buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + buttonlayout->addWidget (recordButton); + source = new QLabel (i18n ("Current source: ") + m_player->source ()->prettyName (), this); + recorder = new QButtonGroup (m_recorders_length, Qt::Vertical, i18n ("Recorder"), this); + for (RecorderPage * p = m_recorders; p; p = p->next) + new QRadioButton (p->name (), recorder); + if (m_player->source ()) + sourceChanged (0L, m_player->source ()); + recorder->setButton(0); // for now + replay = new QButtonGroup (4, Qt::Vertical, i18n ("Auto Playback"), this); + new QRadioButton (i18n ("&No"), replay); + new QRadioButton (i18n ("&When recording finished"), replay); + new QRadioButton (i18n ("A&fter"), replay); + QWidget * customreplay = new QWidget (replay); + replaytime = new QLineEdit (customreplay); + QHBoxLayout *replaylayout = new QHBoxLayout (customreplay); + replaylayout->addWidget (new QLabel (i18n("Time (seconds):"), customreplay)); + replaylayout->addWidget (replaytime); + replaylayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + layout->addWidget (source); + layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + layout->addLayout (urllayout); + layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + layout->addWidget (recorder); + layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + layout->addWidget (replay); + layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); + layout->addLayout (buttonlayout); + layout->addItem (new QSpacerItem (5, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + connect (m_player, SIGNAL (sourceChanged(KMPlayer::Source*,KMPlayer::Source*)), this, SLOT (sourceChanged(KMPlayer::Source*,KMPlayer::Source*))); +#ifdef HAVE_XINE + connect (recorder, SIGNAL (clicked(int)), this, SLOT(recorderClicked(int))); +#endif + connect (replay, SIGNAL (clicked (int)), this, SLOT (replayClicked (int))); +} + +KDE_NO_EXPORT void PrefRecordPage::recordingStarted () { + recordButton->setText (i18n ("Stop Recording")); + url->setEnabled (false); + topLevelWidget ()->hide (); +} + +KDE_NO_EXPORT void PrefRecordPage::recordingFinished () { + recordButton->setText (i18n ("Start Recording")); + url->setEnabled (true); + QTimer::singleShot (0, m_player, SLOT(recordingStopped())); // removed from PartBase::setSource because PartBase::recordingStopped calls openURL and that will call PartBase::setSource and Qt doesn't like disconnecting/connecting a signal that is current +} + +KDE_NO_EXPORT void PrefRecordPage::sourceChanged (Source * olds, Source * nws) { + int id = 0; + int nr_recs = 0; + if (olds) { + disconnect(nws,SIGNAL(startRecording()),this, SLOT(recordingStarted())); + disconnect(nws,SIGNAL(stopRecording()),this, SLOT(recordingFinished())); + } + if (nws) { + for (RecorderPage * p = m_recorders; p; p = p->next, ++id) { + QButton * radio = recorder->find (id); + bool b = m_player->recorders () [p->recorderName ()]->supports (nws->name ()); + radio->setEnabled (b); + if (b) nr_recs++; + } + source->setText (i18n ("Current Source: ") + nws->prettyName ()); + connect (nws, SIGNAL(startRecording()), this, SLOT(recordingStarted())); + connect (nws, SIGNAL(stopRecording()), this, SLOT(recordingFinished())); + } + recordButton->setEnabled (nr_recs > 0); +} + +KDE_NO_EXPORT void PrefRecordPage::recorderClicked (int id) { + bool b = recorder->find(id)->text().find (QString::fromLatin1("Xine")) > -1; + replay->setEnabled (!b); + if (b) + replay->setButton (Settings::ReplayNo); + +} + +KDE_NO_EXPORT void PrefRecordPage::replayClicked (int id) { + replaytime->setEnabled (id == Settings::ReplayAfter); +} + +KDE_NO_EXPORT void PrefRecordPage::slotRecord () { + connect (m_player->source (), SIGNAL (stopPlaying ()), + this, SLOT (playingStopped ())); + if (m_player->process () && m_player->process ()->playing ()) + m_player->process ()->quit (); + else + playingStopped (); +} + +KDE_NO_EXPORT void PrefRecordPage::playingStopped () { + disconnect (m_player->source (), SIGNAL (stopPlaying ()), + this, SLOT (playingStopped ())); + if (!url->lineEdit()->text().isEmpty()) { + m_player->settings ()->recordfile = url->lineEdit()->text(); + m_player->settings ()->replaytime = replaytime->text ().toInt (); +#if KDE_IS_VERSION(3,1,90) + int id = recorder->selectedId (); + int replayid = replay->selectedId (); +#else + int id = recorder->id (recorder->selected ()); + int replayid = replay->id (replay->selectedId ()); +#endif + m_player->settings ()->recorder = Settings::Recorder (id); + m_player->settings ()->replayoption = Settings::ReplayOption (replayid); + for (RecorderPage * p = m_recorders; p; p = p->next) + if (id-- == 0) { + p->record (); + break; + } + } +} + +KDE_NO_CDTOR_EXPORT RecorderPage::RecorderPage (QWidget *parent, PartBase * player) + : QFrame (parent), next (0L), m_player (player) {} + +KDE_NO_EXPORT void RecorderPage::record () { + Process * proc = m_player->recorders () [recorderName ()]; + m_player->setRecorder (recorderName ()); + Recorder * rec = dynamic_cast <Recorder *> (proc); + if (!proc->playing ()) { + if (m_player->process ()) + m_player->process ()->quit (); + rec->setURL (KURL (m_player->settings ()->recordfile)); + proc->setSource (m_player->source ()); + proc->ready (0L); + } else { + rec->setURL (KURL ()); + proc->stop (); + } +} + +KDE_NO_CDTOR_EXPORT PrefMEncoderPage::PrefMEncoderPage (QWidget *parent, PartBase * player) : RecorderPage (parent, player) { + QVBoxLayout *layout = new QVBoxLayout (this, 5, 5); + format = new QButtonGroup (3, Qt::Vertical, i18n ("Format"), this); + new QRadioButton (i18n ("Same as source"), format); + new QRadioButton (i18n ("Custom"), format); + QWidget * customopts = new QWidget (format); + QGridLayout *gridlayout = new QGridLayout (customopts, 1, 2, 2); + QLabel *argLabel = new QLabel (i18n("Mencoder arguments:"), customopts, 0); + arguments = new QLineEdit ("", customopts); + gridlayout->addWidget (argLabel, 0, 0); + gridlayout->addWidget (arguments, 0, 1); + layout->addWidget (format); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + connect (format, SIGNAL (clicked (int)), this, SLOT (formatClicked (int))); +} + +KDE_NO_EXPORT void PrefMEncoderPage::formatClicked (int id) { + arguments->setEnabled (!!id); +} + +KDE_NO_EXPORT void PrefMEncoderPage::record () { +#if KDE_IS_VERSION(3,1,90) + m_player->settings ()->recordcopy = !format->selectedId (); +#else + m_player->settings ()->recordcopy = !format->id (format->selected ()); +#endif + m_player->settings ()->mencoderarguments = arguments->text (); + RecorderPage::record (); +} + +KDE_NO_EXPORT QString PrefMEncoderPage::name () { + return i18n ("&MEncoder"); +} + +KDE_NO_CDTOR_EXPORT PrefMPlayerDumpstreamPage::PrefMPlayerDumpstreamPage (QWidget *parent, PartBase * player) : RecorderPage (parent, player) { + hide(); +} + +KDE_NO_EXPORT QString PrefMPlayerDumpstreamPage::name () { + return i18n ("MPlayer -&dumpstream"); +} + +KDE_NO_CDTOR_EXPORT PrefFFMpegPage::PrefFFMpegPage (QWidget *parent, PartBase * player) : RecorderPage (parent, player) { + QVBoxLayout *layout = new QVBoxLayout (this, 5, 5); + QGridLayout *gridlayout = new QGridLayout (1, 2, 2); + QLabel *argLabel = new QLabel (i18n("FFMpeg arguments:"), this); + arguments = new QLineEdit ("", this); + gridlayout->addWidget (argLabel, 0, 0); + gridlayout->addWidget (arguments, 0, 1); + layout->addLayout (gridlayout); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +KDE_NO_EXPORT void PrefFFMpegPage::record () { + m_player->settings ()->ffmpegarguments = arguments->text (); + RecorderPage::record (); +} + +KDE_NO_EXPORT QString PrefFFMpegPage::name () { + return i18n ("&FFMpeg"); +} + +#ifdef HAVE_XINE +KDE_NO_CDTOR_EXPORT PrefXinePage::PrefXinePage (QWidget *parent, PartBase * player) : RecorderPage (parent, player) { + hide(); +} + +KDE_NO_EXPORT QString PrefXinePage::name () { + return i18n ("&Xine"); +} +#endif + +KDE_NO_CDTOR_EXPORT PrefGeneralPageOutput::PrefGeneralPageOutput(QWidget *parent, OutputDriver * ad, OutputDriver * vd) + : QFrame (parent) { + QGridLayout *layout = new QGridLayout (this, 2, 2, 5); + + videoDriver = new QListBox (this); + for (int i = 0; vd[i].driver; i++) + videoDriver->insertItem (vd[i].description, i); + QWhatsThis::add(videoDriver, i18n("Sets video driver. Recommended is XVideo, or, if it is not supported, X11, which is slower.")); + layout->addWidget (new QLabel (i18n ("Video driver:"), this), 0, 0); + layout->addWidget (videoDriver, 1, 0); + + audioDriver = new QListBox (this); + for (int i = 0; ad[i].driver; i++) + audioDriver->insertItem (ad[i].description, i); + layout->addWidget (new QLabel (i18n ("Audio driver:"), this), 0, 1); + layout->addWidget (audioDriver, 1, 1); + layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); +} + +KDE_NO_CDTOR_EXPORT PrefOPPageGeneral::PrefOPPageGeneral(QWidget *parent) +: QFrame(parent) +{ + QVBoxLayout *layout = new QVBoxLayout (this, 5); + layout->setAutoAdd (true); +} + +KDE_NO_CDTOR_EXPORT PrefOPPagePostProc::PrefOPPagePostProc(QWidget *parent) : QFrame(parent) +{ + QVBoxLayout *tabLayout = new QVBoxLayout (this, 5); + postProcessing = new QCheckBox (i18n ("Enable use of postprocessing filters"), this); + postProcessing->setEnabled( true ); + disablePPauto = new QCheckBox (i18n ("Disable use of postprocessing when watching TV/DVD"), this); + + tabLayout->addWidget( postProcessing ); + tabLayout->addWidget( disablePPauto ); + tabLayout->addItem ( new QSpacerItem( 5, 5, QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + + PostprocessingOptions = new QTabWidget( this, "PostprocessingOptions" ); + PostprocessingOptions->setEnabled (true); + PostprocessingOptions->setAutoMask (false); + PostprocessingOptions->setTabPosition( QTabWidget::Top ); + PostprocessingOptions->setTabShape( QTabWidget::Rounded ); + PostprocessingOptions->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)1, PostprocessingOptions->sizePolicy().hasHeightForWidth() ) ); + + QWidget *presetSelectionWidget = new QWidget( PostprocessingOptions, "presetSelectionWidget" ); + QGridLayout *presetSelectionWidgetLayout = new QGridLayout( presetSelectionWidget, 1, 1, 1); + + QButtonGroup *presetSelection = new QButtonGroup(3, Qt::Vertical, presetSelectionWidget); + presetSelection->setInsideSpacing(KDialog::spacingHint()); + + defaultPreset = new QRadioButton (i18n ("Default"), presetSelection); + defaultPreset->setChecked( true ); + presetSelection->insert (defaultPreset); + + customPreset = new QRadioButton (i18n ("Custom"), presetSelection); + presetSelection->insert (customPreset); + + fastPreset = new QRadioButton (i18n ("Fast"), presetSelection); + presetSelection->insert (fastPreset); + presetSelection->setRadioButtonExclusive ( true); + presetSelectionWidgetLayout->addWidget( presetSelection, 0, 0 ); + PostprocessingOptions->insertTab( presetSelectionWidget, "" ); + + // + // SECOND!!! + // + /* I JUST WASN'T ABLE TO GET THIS WORKING WITH QGridLayouts */ + + QWidget *customFiltersWidget = new QWidget( PostprocessingOptions, "customFiltersWidget" ); + QVBoxLayout *customFiltersWidgetLayout = new QVBoxLayout( customFiltersWidget ); + + QGroupBox *customFilters = new QGroupBox(0, Qt::Vertical, customFiltersWidget, "customFilters" ); + customFilters->setSizePolicy(QSizePolicy((QSizePolicy::SizeType)1, (QSizePolicy::SizeType)2)); + customFilters->setFlat(false); + customFilters->setEnabled( false ); + customFilters->setInsideSpacing(7); + + QLayout *customFiltersLayout = customFilters->layout(); + QHBoxLayout *customFiltersLayout1 = new QHBoxLayout ( customFilters->layout() ); + + HzDeblockFilter = new QCheckBox (i18n ("Horizontal deblocking"), customFilters); + HzDeblockAQuality = new QCheckBox (i18n ("Auto quality"), customFilters); + HzDeblockAQuality->setEnabled (false); + HzDeblockCFiltering = new QCheckBox (i18n ("Chrominance filtering"), customFilters); + HzDeblockCFiltering->setEnabled (false); + + customFiltersLayout1->addWidget( HzDeblockFilter ); + customFiltersLayout1->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + customFiltersLayout1->addWidget( HzDeblockAQuality ); + customFiltersLayout1->addWidget( HzDeblockCFiltering ); + + QFrame *line1 = new QFrame( customFilters, "line1" ); + line1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)2 ) ); + line1->setFrameShape( QFrame::HLine ); + line1->setFrameShadow( QFrame::Sunken ); + customFiltersLayout->add(line1); + + QHBoxLayout *customFiltersLayout2 = new QHBoxLayout ( customFilters->layout() ); + + VtDeblockFilter = new QCheckBox(i18n("Vertical deblocking"), customFilters); + VtDeblockAQuality = new QCheckBox (i18n ("Auto quality"), customFilters); + VtDeblockAQuality->setEnabled (false); + VtDeblockCFiltering = new QCheckBox (i18n ("Chrominance filtering"), customFilters); + VtDeblockCFiltering->setEnabled (false); + + customFiltersLayout2->addWidget( VtDeblockFilter ); + customFiltersLayout2->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + customFiltersLayout2->addWidget( VtDeblockAQuality ); + customFiltersLayout2->addWidget( VtDeblockCFiltering ); + + QFrame *line2 = new QFrame( customFilters, "line2" ); + + line2->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)2 ) ); + line2->setFrameShape( QFrame::HLine ); + line2->setFrameShadow( QFrame::Sunken ); + customFiltersLayout->add(line2); + + QHBoxLayout *customFiltersLayout3 = new QHBoxLayout ( customFilters->layout() ); + + DeringFilter = new QCheckBox (i18n ("Dering filter"), customFilters); + DeringAQuality = new QCheckBox (i18n ("Auto quality"), customFilters); + DeringAQuality->setEnabled (false); + DeringCFiltering=new QCheckBox(i18n("Chrominance filtering"),customFilters); + DeringCFiltering->setEnabled (false); + + customFiltersLayout3->addWidget( DeringFilter ); + customFiltersLayout3->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + customFiltersLayout3->addWidget( DeringAQuality ); + customFiltersLayout3->addWidget( DeringCFiltering ); + + QFrame *line3 = new QFrame( customFilters, "line3" ); + line3->setFrameShape( QFrame::HLine ); + line3->setFrameShadow( QFrame::Sunken ); + line3->setFrameShape( QFrame::HLine ); + + customFiltersLayout->add(line3); + + QHBoxLayout *customFiltersLayout4 =new QHBoxLayout(customFilters->layout()); + + AutolevelsFilter = new QCheckBox (i18n ("Auto brightness/contrast"), customFilters); + AutolevelsFullrange = new QCheckBox (i18n ("Stretch luminance to full range"), customFilters); + AutolevelsFullrange->setEnabled (false); + + customFiltersLayout4->addWidget(AutolevelsFilter); + customFiltersLayout4->addItem(new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum )); + customFiltersLayout4->addWidget(AutolevelsFullrange); + + QHBoxLayout *customFiltersLayout5 = new QHBoxLayout (customFilters->layout()); + + TmpNoiseFilter =new QCheckBox(i18n("Temporal noise reducer"),customFilters); + /* Note: Change TmpNoiseFilter text back to "Label:" if this slider gets reactivated + TmpNoiseSlider = new QSlider( customFilters, "TmpNoiseSlider" ); + TmpNoiseSlider->setEnabled( false ); + TmpNoiseSlider->setMinValue( 1 ); + TmpNoiseSlider->setMaxValue( 3 ); + TmpNoiseSlider->setValue( 1 ); + TmpNoiseSlider->setOrientation( QSlider::Horizontal ); + TmpNoiseSlider->setTickmarks( QSlider::Left ); + TmpNoiseSlider->setTickInterval( 1 ); + TmpNoiseSlider->setSizePolicy(QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)1));*/ + + /*customFiltersLayout->addWidget(TmpNoiseFilter,7,0); + customFiltersLayout->addWidget(TmpNoiseSlider,7,2);*/ + customFiltersLayout5->addWidget(TmpNoiseFilter); + customFiltersLayout5->addItem(new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum )); + //customFiltersLayout5->addWidget(TmpNoiseSlider); + customFiltersWidgetLayout->addWidget( customFilters ); + PostprocessingOptions->insertTab( customFiltersWidget, "" ); + // + //THIRD!!! + // + QWidget *deintSelectionWidget = new QWidget( PostprocessingOptions, "deintSelectionWidget" ); + QVBoxLayout *deintSelectionWidgetLayout = new QVBoxLayout( deintSelectionWidget); + QButtonGroup *deinterlacingGroup = new QButtonGroup(5, Qt::Vertical, deintSelectionWidget, "deinterlacingGroup" ); + + LinBlendDeinterlacer = new QCheckBox (i18n ("Linear blend deinterlacer"), deinterlacingGroup); + LinIntDeinterlacer = new QCheckBox (i18n ("Linear interpolating deinterlacer"), deinterlacingGroup); + CubicIntDeinterlacer = new QCheckBox (i18n ("Cubic interpolating deinterlacer"), deinterlacingGroup); + MedianDeinterlacer = new QCheckBox (i18n ("Median deinterlacer"), deinterlacingGroup); + FfmpegDeinterlacer = new QCheckBox (i18n ("FFmpeg deinterlacer"), deinterlacingGroup); + + deinterlacingGroup->insert( LinBlendDeinterlacer ); + deinterlacingGroup->insert( LinIntDeinterlacer ); + deinterlacingGroup->insert( CubicIntDeinterlacer ); + deinterlacingGroup->insert( MedianDeinterlacer ); + deinterlacingGroup->insert( FfmpegDeinterlacer ); + + deintSelectionWidgetLayout->addWidget( deinterlacingGroup, 0, 0 ); + + PostprocessingOptions->insertTab( deintSelectionWidget, "" ); + + tabLayout->addWidget( PostprocessingOptions/*, 1, 0*/ ); + + PostprocessingOptions->setEnabled(false); + connect( customPreset, SIGNAL (toggled(bool) ), customFilters, SLOT(setEnabled(bool))); + connect( postProcessing, SIGNAL( toggled(bool) ), PostprocessingOptions, SLOT( setEnabled(bool) ) ); + connect( HzDeblockFilter, SIGNAL( toggled(bool) ), HzDeblockAQuality, SLOT( setEnabled(bool) ) ); + connect( HzDeblockFilter, SIGNAL( toggled(bool) ), HzDeblockCFiltering, SLOT( setEnabled(bool) ) ); + connect( VtDeblockFilter, SIGNAL( toggled(bool) ), VtDeblockCFiltering, SLOT( setEnabled(bool) ) ); + connect( VtDeblockFilter, SIGNAL( toggled(bool) ), VtDeblockAQuality, SLOT( setEnabled(bool) ) ); + connect( DeringFilter, SIGNAL( toggled(bool) ), DeringAQuality, SLOT( setEnabled(bool) ) ); + connect( DeringFilter, SIGNAL( toggled(bool) ), DeringCFiltering, SLOT( setEnabled(bool) ) ); + //connect( TmpNoiseFilter, SIGNAL( toggled(bool) ), TmpNoiseSlider, SLOT( setEnabled(bool) ) ); + + connect( AutolevelsFilter, SIGNAL( toggled(bool) ), AutolevelsFullrange, SLOT( setEnabled(bool) ) ); + + QWhatsThis::add( defaultPreset, i18n( "Enable mplayer's default postprocessing filters" ) ); + QWhatsThis::add( customPreset, i18n( "Enable custom postprocessing filters (See: Custom preset -tab)" ) ); + QWhatsThis::add( fastPreset, i18n( "Enable mplayer's fast postprocessing filters" ) ); + PostprocessingOptions->changeTab( presetSelectionWidget, i18n( "General" ) ); + customFilters->setTitle (QString ()); + QWhatsThis::add( HzDeblockAQuality, i18n( "Filter is used if there is enough CPU" ) ); + QWhatsThis::add( VtDeblockAQuality, i18n( "Filter is used if there is enough CPU" ) ); + QWhatsThis::add( DeringAQuality, i18n( "Filter is used if there is enough CPU" ) ); + //QWhatsThis::add( TmpNoiseSlider, i18n( "Strength of the noise reducer" ) ); + QWhatsThis::add( AutolevelsFullrange, i18n( "Stretches luminance to full range (0..255)" ) ); + PostprocessingOptions->changeTab( customFiltersWidget, i18n( "Custom Preset" ) ); + deinterlacingGroup->setTitle (QString ()); + PostprocessingOptions->changeTab( deintSelectionWidget, i18n( "Deinterlacing" ) ); + PostprocessingOptions->adjustSize(); +} + +KDE_NO_EXPORT void Preferences::confirmDefaults() { + // TODO: Switch to KMessageBox + switch( QMessageBox::warning( this, i18n("Reset Settings?"), + i18n("You are about to have all your settings overwritten with defaults.\nPlease confirm.\n"), + i18n ("&OK"), i18n ("&Cancel"), QString (), 0, 1)) { + case 0: Preferences::setDefaults(); + break; + case 1: break; + } + +} + +KDE_NO_EXPORT void Preferences::setDefaults() { + m_GeneralPageGeneral->keepSizeRatio->setChecked(true); + m_GeneralPageGeneral->loop->setChecked(false); + m_GeneralPageGeneral->seekTime->setValue(10); + + m_GeneralPageOutput->videoDriver->setCurrentItem (0); + m_GeneralPageOutput->audioDriver->setCurrentItem(0); + + m_OPPagePostproc->postProcessing->setChecked(false); + m_OPPagePostproc->disablePPauto->setChecked(true); + + m_OPPagePostproc->defaultPreset->setChecked(true); + + m_OPPagePostproc->LinBlendDeinterlacer->setChecked(false); + m_OPPagePostproc->LinIntDeinterlacer->setChecked(false); + m_OPPagePostproc->CubicIntDeinterlacer->setChecked(false); + m_OPPagePostproc->MedianDeinterlacer->setChecked(false); + m_OPPagePostproc->FfmpegDeinterlacer->setChecked(false); + +} +#include "pref.moc" diff --git a/src/pref.h b/src/pref.h new file mode 100644 index 0000000..c7d6166 --- /dev/null +++ b/src/pref.h @@ -0,0 +1,320 @@ +/** + * Copyright (C) 2003 Joonas Koivunen <[email protected]> + * Copyright (C) 2003 Koos Vriezen <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KMPlayerPREF_H_ +#define _KMPlayerPREF_H_ + +#include "kmplayer_def.h" + +#include <kdialogbase.h> +#include <qframe.h> +#include <qmap.h> + +class QTabWidget; +class QTable; +class QGroupBox; +class QCheckBox; +class QComboBox; +class QLineEdit; +class QRadioButton; +class QSlider; +class QSpinBox; +class QColor; +class QButtonGroup; +class KHistoryCombo; +class KComboBox; +class KURLRequester; +class KColorButton; + +namespace KMPlayer { + +class PrefGeneralPageGeneral; // general, general +class PrefSourcePageURL; // source, url +class PrefRecordPage; // recording +class RecorderPage; // base recorder +class PrefMEncoderPage; // mencoder +class PrefMPlayerDumpstreamPage; // mplayer -dumpstream +class PrefFFMpegPage; // ffmpeg +class PrefXinePage; // xine url:record +class PrefGeneralPageLooks; // general, looks +class PrefGeneralPageOutput; // general, output +class PrefOPPageGeneral; // OP = outputplugins, general +class PrefOPPagePostProc; // outputplugins, postproc +class PartBase; +class Source; +class Settings; +class PreferencesPage; +class OutputDriver; +class ColorSetting; +class FontSetting; + +class KMPLAYER_NO_EXPORT Preferences : public KDialogBase +{ + Q_OBJECT +public: + + Preferences(PartBase *, Settings *); + ~Preferences(); + + PrefGeneralPageGeneral *m_GeneralPageGeneral; + PrefSourcePageURL *m_SourcePageURL; + PrefRecordPage *m_RecordPage; + PrefMEncoderPage *m_MEncoderPage; + PrefMPlayerDumpstreamPage *m_MPlayerDumpstreamPage; +#ifdef HAVE_XINE + PrefXinePage *m_XinePage; +#endif + PrefFFMpegPage *m_FFMpegPage; + PrefGeneralPageLooks *m_GeneralPageLooks; + PrefGeneralPageOutput *m_GeneralPageOutput; + PrefOPPageGeneral *m_OPPageGeneral; + PrefOPPagePostProc *m_OPPagePostproc; + void setDefaults(); + void setPage (const char *); + void addPrefPage (PreferencesPage *); + void removePrefPage (PreferencesPage *); + + RecorderPage * recorders; + QMap<QString, QTabWidget *> entries; +public slots: + void confirmDefaults(); +}; + +class KMPLAYER_NO_EXPORT PrefGeneralPageGeneral : public QFrame +{ + Q_OBJECT +public: + PrefGeneralPageGeneral(QWidget *parent, Settings *); + ~PrefGeneralPageGeneral() {} + + QCheckBox *keepSizeRatio; + QCheckBox * autoResize; + QButtonGroup *sizesChoice; + QCheckBox *dockSysTray; + QCheckBox *loop; + QCheckBox *showConfigButton; + QCheckBox *showPlaylistButton; + QCheckBox *showRecordButton; + QCheckBox *showBroadcastButton; + QCheckBox *framedrop; + QCheckBox *adjustvolume; + QCheckBox *adjustcolors; + + QSpinBox *seekTime; +}; + +class KMPLAYER_NO_EXPORT PrefGeneralPageLooks : public QFrame { + Q_OBJECT +public: + PrefGeneralPageLooks (QWidget *parent, Settings *); + ~PrefGeneralPageLooks () {} + QComboBox *colorscombo; + KColorButton *colorbutton; + QComboBox *fontscombo; + QPushButton *fontbutton; +public slots: + void colorItemChanged (int); + void colorCanged (const QColor &); + void fontItemChanged (int); + void fontClicked (); +private: + ColorSetting * colors; + FontSetting * fonts; +}; + +class KMPLAYER_NO_EXPORT PrefSourcePageURL : public QFrame +{ + Q_OBJECT +public: + PrefSourcePageURL (QWidget *parent); + ~PrefSourcePageURL () {} + + KURLRequester * url; + //KHistoryCombo * url; + KComboBox * urllist; + KURLRequester * sub_url; + KComboBox * sub_urllist; + QListBox * backend; + QCheckBox * allowhref; + QLineEdit * prefBitRate; + QLineEdit * maxBitRate; + bool changed; +private slots: + void slotBrowse (); + void slotTextChanged (const QString &); +}; + + +class KMPLAYER_NO_EXPORT PrefRecordPage : public QFrame +{ + Q_OBJECT +public: + PrefRecordPage (QWidget *parent, PartBase *, RecorderPage *, int len); + ~PrefRecordPage () {} + + KURLRequester * url; + QButtonGroup * recorder; + QButtonGroup * replay; + QLineEdit * replaytime; + QLabel * source; +public slots: + void replayClicked (int id); + void recorderClicked (int id); +private slots: + void slotRecord (); + void playingStopped (); + void sourceChanged (KMPlayer::Source *, KMPlayer::Source *); + void recordingStarted (); + void recordingFinished (); +private: + PartBase * m_player; + RecorderPage * m_recorders; + QPushButton * recordButton; + int m_recorders_length; +}; + +class KMPLAYER_NO_EXPORT RecorderPage : public QFrame +{ + Q_OBJECT +public: + RecorderPage (QWidget *parent, PartBase *); + virtual ~RecorderPage () {}; + virtual void record (); + virtual QString name () = 0; + virtual const char * recorderName () = 0; + RecorderPage * next; +protected: + PartBase * m_player; +}; + +class KMPLAYER_NO_EXPORT PrefMEncoderPage : public RecorderPage +{ + Q_OBJECT +public: + PrefMEncoderPage (QWidget *parent, PartBase *); + ~PrefMEncoderPage () {} + + void record (); + QString name (); + const char * recorderName () { return "mencoder"; } + + QLineEdit * arguments; + QButtonGroup * format; +public slots: + void formatClicked (int id); +private: +}; + +class KMPLAYER_NO_EXPORT PrefMPlayerDumpstreamPage : public RecorderPage { +public: + PrefMPlayerDumpstreamPage (QWidget *parent, PartBase *); + ~PrefMPlayerDumpstreamPage () {} + + QString name (); + const char * recorderName () { return "mplayerdumpstream"; } +}; + +#ifdef HAVE_XINE +class KMPLAYER_NO_EXPORT PrefXinePage : public RecorderPage { +public: + PrefXinePage (QWidget *parent, PartBase *); + ~PrefXinePage () {} + + QString name (); + const char * recorderName () { return "xine"; } +}; +#endif + +class KMPLAYER_NO_EXPORT PrefFFMpegPage : public RecorderPage +{ + Q_OBJECT +public: + PrefFFMpegPage (QWidget *parent, PartBase *); + ~PrefFFMpegPage () {} + + void record (); + QString name (); + const char * recorderName () { return "ffmpeg"; } + + QLineEdit * arguments; + QButtonGroup * format; +private: +}; + + +class KMPLAYER_NO_EXPORT PrefGeneralPageOutput : public QFrame +{ + Q_OBJECT +public: + PrefGeneralPageOutput (QWidget *parent, OutputDriver * ad, OutputDriver * vd); + ~PrefGeneralPageOutput() {} + + QListBox *videoDriver; + QListBox *audioDriver; +}; + +class KMPLAYER_NO_EXPORT PrefOPPageGeneral : public QFrame +{ + Q_OBJECT +public: + PrefOPPageGeneral(QWidget *parent = 0); + ~PrefOPPageGeneral() {} +}; + +class KMPLAYER_NO_EXPORT PrefOPPagePostProc : public QFrame +{ + Q_OBJECT +public: + PrefOPPagePostProc(QWidget *parent = 0); + ~PrefOPPagePostProc() {} + + QCheckBox* postProcessing; + QCheckBox* disablePPauto; + QTabWidget* PostprocessingOptions; + + QRadioButton* defaultPreset; + QRadioButton* customPreset; + QRadioButton* fastPreset; + + QCheckBox* HzDeblockFilter; + QCheckBox* VtDeblockFilter; + QCheckBox* DeringFilter; + QCheckBox* HzDeblockAQuality; + QCheckBox* VtDeblockAQuality; + QCheckBox* DeringAQuality; + + QCheckBox* AutolevelsFilter; + QCheckBox* AutolevelsFullrange; + QCheckBox* HzDeblockCFiltering; + QCheckBox* VtDeblockCFiltering; + QCheckBox* DeringCFiltering; + QCheckBox* TmpNoiseFilter; + QSlider* TmpNoiseSlider; + + QCheckBox* LinBlendDeinterlacer; + QCheckBox* CubicIntDeinterlacer; + QCheckBox* LinIntDeinterlacer; + QCheckBox* MedianDeinterlacer; + QCheckBox* FfmpegDeinterlacer; +}; + +} // namespace + +#endif // _KMPlayerPREF_H_ diff --git a/src/subtrans.txt b/src/subtrans.txt new file mode 100644 index 0000000..5845890 --- /dev/null +++ b/src/subtrans.txt @@ -0,0 +1,19 @@ +{ "circle", SMIL::Transition::SubCircle }, +{ "clockwiseNine", SMIL::Transition::SubClockwiseNine }, +{ "clockwiseSix", SMIL::Transition::SubClockwiseSix }, +{ "clockwiseThree", SMIL::Transition::SubClockwiseThree }, +{ "clockwiseTwelve",SMIL::Transition::SubClockwiseTwelve }, +{ "crossfade", SMIL::Transition::SubCrossfade }, +{ "diamond", SMIL::Transition::SubDiamond }, +{ "fadeFromColor", SMIL::Transition::SubFadeFromColor }, +{ "fadeToColor", SMIL::Transition::SubFadeToColor }, +{ "fromBottom", SMIL::Transition::SubFromBottom }, +{ "fromLeft", SMIL::Transition::SubFromLeft }, +{ "fromRight", SMIL::Transition::SubFromRight }, +{ "fromTop", SMIL::Transition::SubFromTop }, +{ "horizontal", SMIL::Transition::SubHorizontal }, +{ "leftToRight", SMIL::Transition::SubLeftToRight }, +{ "rectangle", SMIL::Transition::SubRectangle }, +{ "topToBottom", SMIL::Transition::SubTopToBottom }, +{ "vertical", SMIL::Transition::SubVertical }, +{ NULL, SMIL::Transition::SubTransLast } diff --git a/src/transitions.txt b/src/transitions.txt new file mode 100644 index 0000000..d23712f --- /dev/null +++ b/src/transitions.txt @@ -0,0 +1,29 @@ +/*http://www.w3.org/TR/2005/REC-SMIL2-20050107/smil-transitions.html#Table%201:%20Taxonomy%20Table*/ +{ "barWipe", SMIL::Transition::BarWipe, 2, { + SMIL::Transition::SubLeftToRight, + SMIL::Transition::SubTopToBottom } }, +{ "bowTieWipe", SMIL::Transition::BowTieWipe, 2, { + SMIL::Transition::SubVertical, + SMIL::Transition::SubHorizontal } }, +{ "clockWipe", SMIL::Transition::ClockWipe, 4, { + SMIL::Transition::SubClockwiseTwelve, + SMIL::Transition::SubClockwiseThree, + SMIL::Transition::SubClockwiseSix, + SMIL::Transition::SubClockwiseNine } }, +{ "ellipseWipe",SMIL::Transition::EllipseWipe,3, { + SMIL::Transition::SubCircle, + SMIL::Transition::SubVertical, + SMIL::Transition::SubHorizontal } }, +{ "fade", SMIL::Transition::Fade, 3, { + SMIL::Transition::SubCrossfade, + SMIL::Transition::SubFadeToColor, + SMIL::Transition::SubFadeFromColor } }, +{ "irisWipe", SMIL::Transition::IrisWipe, 2, { + SMIL::Transition::SubRectangle, SMIL::Transition::SubDiamond } }, +{ "pushWipe", SMIL::Transition::PushWipe, 4, { + SMIL::Transition::SubFromLeft, + SMIL::Transition::SubFromTop, + SMIL::Transition::SubFromRight, + SMIL::Transition::SubFromBottom } }, +{ NULL, SMIL::Transition::TransTypeNone, 0, { + } } diff --git a/src/triestring.cpp b/src/triestring.cpp new file mode 100644 index 0000000..bf41506 --- /dev/null +++ b/src/triestring.cpp @@ -0,0 +1,516 @@ +/** + This file belong to the KMPlayer project, a movie player plugin for Konqueror + Copyright (C) 2007 Koos Vriezen <[email protected]> + + 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 +**/ + +#ifdef TEST_TRIE +# define KMPLAYER_NO_EXPORT +# define KMPLAYER_EXPORT +# define KDE_NO_EXPORT +# define KDE_NO_CDTOR_EXPORT +#else +# include <config.h> +# include "kmplayer_def.h" +#endif +#include <stdio.h> +#include <stdlib.h> + + +#include "triestring.h" + +namespace KMPlayer { + +struct KMPLAYER_NO_EXPORT TrieNode { + TrieNode (const char * s); + ~TrieNode (); + void unref (); + void removeChild (TrieNode *); + void dump (int lvl) { + QString indent (QString ().fill (QChar ('.'), lvl)); + printf("%s%s len:%4d rc:%4d\n", indent.ascii(), str, length, ref_count); + } + char * str; + unsigned short length; + unsigned short ref_count; + TrieNode * parent; + TrieNode * first_child; + TrieNode * next_sibling; +}; + +} + +using namespace KMPlayer; + +static TrieNode * root_trie; + +void dump (TrieNode * node, int lvl) { + if (!node) + return; + node->dump (lvl); + dump (node->first_child, lvl+2); + if (node->next_sibling) + dump (node->next_sibling, lvl); +} + +KDE_NO_CDTOR_EXPORT TrieNode::TrieNode (const char * s) + : str (s ? strdup (s) : 0L), + length (s ? strlen (s) : 0), + ref_count (1), + parent (0L), + first_child (0L), + next_sibling (0L) {} + +KDE_NO_CDTOR_EXPORT TrieNode::~TrieNode () { + if (str) + free (str); +} + +KDE_NO_EXPORT void TrieNode::unref () { + if (--ref_count <= 0 && !first_child) + parent->removeChild (this); +} + +KDE_NO_EXPORT void TrieNode::removeChild (TrieNode * node) { + if (node == first_child) { + first_child = node->next_sibling; + } else { + for (TrieNode *tn = first_child; tn; tn = tn->next_sibling) + if (tn->next_sibling == node) { + tn->next_sibling = node->next_sibling; + break; + } + } + delete node; + if (!parent) + return; + if (!ref_count && !first_child) + parent->removeChild (this); // can this happen ? + else if (!ref_count && !first_child->next_sibling) { // merge with child + char * tmp = first_child->str; + first_child->length = first_child->length + length; + first_child->str = (char *) malloc (first_child->length + 1); + strcpy (first_child->str, str); + strcat (first_child->str, tmp); + free (tmp); + first_child->parent = parent; + first_child->next_sibling = next_sibling; + if (parent->first_child == this) { + parent->first_child = first_child; + } else { + for (TrieNode *n = parent->first_child; n; n = n->next_sibling) + if (n->next_sibling == this) { + n->next_sibling = first_child; + break; + } + } + delete this; + } +} + +static char * trieRetrieveString (TrieNode * node, int &len) { + char *buf; + if (node->parent) { + len += node->length; + buf = trieRetrieveString (node->parent, len); + strcat (buf, node->str); + } else { + buf = (char *) malloc (len + 1); + *buf = 0; + } + return buf; +} + +static int trieStringCompare (TrieNode * node, const char * s, int &len) { + int cmp = 0; + if (!node) + return !!s; + if (node->parent && node->parent != root_trie) + cmp = trieStringCompare (node->parent, s, len); + if (!cmp) { +#ifdef TEST_TRIE + printf( "compare %s %s %d\n", node->str, s + len, node->length); +#endif + cmp = s ? strncmp (node->str, s + len, node->length) : 1; + len += node->length; + } + return cmp; +} + +static int trieStringCompare (TrieNode * n1, TrieNode * n2) { + // pre n1 && n2 on same depth and not NIL + int cmp = 0; + if (n1->parent && n1->parent != root_trie) + cmp = trieStringCompare (n1->parent, n2->parent); + if (!cmp && n1 != n2) { +#ifdef TEST_TRIE + printf( "compare %s %s", n1->str, n2->str); +#endif + if (!n1->str) + cmp = n2->str ? 1 : 0; + else if (!n2->str) + cmp = 1; + else + cmp = strcmp (n1->str, n2->str); +#ifdef TEST_TRIE + printf( "=> %d\n", cmp); +#endif + } + return cmp; +} + +static int trieStringStarts (TrieNode * node, const char * s, int & pos) { + int cmp = -1; // -1 still matches, 0 no, 1 yes + if (node->parent && node->parent != root_trie) + cmp = trieStringStarts (node->parent, s, pos); + if (cmp == -1) { + for (int i = 0; i < node->length; i++) + if (node->str[i] != s[pos + i]) + return !s[pos + i] ? 1 : 0; + pos += node->length; + } + return cmp; +} + +static TrieNode * trieInsert (const char * s) { + if (!root_trie) + root_trie = new TrieNode (0L); + //printf("trieInsert %s\n", s); + //dumpTrie(); + TrieNode * parent = root_trie; + for (TrieNode * c = parent->first_child; c; c = c->first_child) { + TrieNode * prev = c; + for (TrieNode * n = prev; n; n = n->next_sibling) { + if (n->str[0] == s[0]) { // insert here + int i = 1; + for (; i < n->length; i++) { + if (n->str[i] != s[i]) { // break here + // insert new node so strings to n remain valid + bool bigger = n->str[i] < s[i]; + char *tmp = n->str; + n->str = strdup (tmp + i); + n->length -= i; + tmp[i] = 0; + TrieNode * node = new TrieNode (tmp); + free (tmp); + node->parent = parent; + node->next_sibling = n->next_sibling; + if (prev != n) + prev->next_sibling = node; + else + parent->first_child = node; + n->parent = node; + TrieNode * snode; + if (!s[i]) { + node->first_child = n; + n->next_sibling = 0L; + snode = node; // s is complete in node + } else { + snode = new TrieNode (s+i); + snode->parent = node; + if (bigger) { // set n before snode + node->first_child = n; + n->next_sibling = snode; + } else { // set snode before n + node->first_child = snode; + snode->next_sibling = n; + n->next_sibling = 0L; + } + node->ref_count--; + } + return snode; + } + } + if (s[i]) { // go one level deeper with s+i + s = s + i; + c = n; + prev = 0; + break; + } // else n and s are equal + n->ref_count++; + return n; + } else if (n->str[0] > s[0]) { // insert before + TrieNode * node = new TrieNode (s); + node->parent = parent; + node->next_sibling = n; + if (prev != n) + prev->next_sibling = node; + else + parent->first_child = node; + return node; + } + prev = n; + } + if (prev) { // insert after + TrieNode * node = new TrieNode (s); + node->parent = parent; + prev->next_sibling = node; + return node; + } + parent = c; + } + // hit an empty first_child, add s as first_child + TrieNode * node = new TrieNode (s); + parent->first_child = node; + node->parent = parent; + return node; +} + +TrieString::TrieString (const QString & s) + : node (s.isEmpty () ? 0L : trieInsert (s.utf8 ().data ())) +{} + +TrieString::TrieString (const char * utf8) + : node (!utf8 ? 0L : trieInsert (utf8)) +{} + +TrieString::TrieString (const TrieString & s) : node (s.node) { + if (node) + node->ref_count++; +} + +TrieString::~TrieString () { + if (node) + node->unref (); +} + +bool TrieString::startsWith (const TrieString & s) const { + for (TrieNode * n = node; n; n = n->parent) + if (n == s.node) + return true; + return s.node ? false : true; +} + +bool TrieString::startsWith (const char * str) const { + if (!node) + return !str ? true : false; + if (!str) + return true; + int pos = 0; + return trieStringStarts (node, str, pos) != 0; +} + +void TrieString::clear () { + if (node) + node->unref (); + node = 0L; +} + +TrieString & TrieString::operator = (const TrieString & s) { + if (s.node != node) { + if (s.node) + s.node->ref_count++; + if (node) + node->unref (); + node = s.node; + } + return *this; +} + +TrieString & TrieString::operator = (const char * utf8) { + if (node) + node->unref (); + node = !utf8 ? 0L : trieInsert (utf8); + return *this; +} + +QString TrieString::toString () const { + QString s; + if (node) { + int len = 0; + char *utf8 = trieRetrieveString (node, len); + s = QString::fromUtf8 (utf8); + free (utf8); + } + return s; +} + +bool TrieString::operator < (const TrieString & s) const { + if (node == s.node) + return false; + int depth1 = 0, depth2 = 0; + for (TrieNode * n = node; n; n = n->parent) + depth1++; + if (!depth1) + return s.node ? true : false; + for (TrieNode * n = s.node; n; n = n->parent) + depth2++; + if (!depth2) + return false; + TrieNode * n1 = node; + TrieNode * n2 = s.node; + while (depth1 > depth2) { + if (n1 == n2) + return false; + n1 = n1->parent; + depth1--; + } + while (depth2 > depth1) { + if (n1 == n2) + return true; + n2 = n2->parent; + depth2--; + } + int cmp = trieStringCompare (n1, n2); + if (cmp) + return cmp < 0; + return depth1 < depth2; +} + +bool KMPlayer::operator == (const TrieString & s1, const char * s2) { + int len = 0; + return !trieStringCompare (s1.node, s2, len); +} + + +TrieString StringPool::attr_id; +TrieString StringPool::attr_name; +TrieString StringPool::attr_src; +TrieString StringPool::attr_url; +TrieString StringPool::attr_href; +TrieString StringPool::attr_width; +TrieString StringPool::attr_height; +TrieString StringPool::attr_top; +TrieString StringPool::attr_left; +TrieString StringPool::attr_bottom; +TrieString StringPool::attr_right; +TrieString StringPool::attr_title; +TrieString StringPool::attr_begin; +TrieString StringPool::attr_dur; +TrieString StringPool::attr_end; +TrieString StringPool::attr_region; +TrieString StringPool::attr_target; +TrieString StringPool::attr_type; +TrieString StringPool::attr_value; +TrieString StringPool::attr_fill; + +void StringPool::init() { + attr_width = "width"; + attr_value = "value"; + attr_url = "url"; + attr_type = "type"; + attr_top = "top"; + attr_title = "title"; + attr_target = "target"; + attr_src = "src"; + attr_right = "right"; + attr_region = "region"; + attr_name = "name"; + attr_left = "left"; + attr_id = "id"; + attr_href = "href"; + attr_height = "height"; + attr_fill = "fill"; + attr_end = "end"; + attr_dur = "dur"; + attr_bottom = "bottom"; + attr_begin = "begin"; +} + +void StringPool::reset() { + attr_id.clear (); + attr_name.clear (); + attr_src.clear (); + attr_url.clear (); + attr_href.clear (); + attr_width.clear (); + attr_height.clear (); + attr_top.clear (); + attr_left.clear (); + attr_bottom.clear (); + attr_right.clear (); + attr_title.clear (); + attr_begin.clear (); + attr_dur.clear (); + attr_end.clear (); + attr_region.clear (); + attr_target.clear (); + attr_type.clear (); + attr_value.clear (); + attr_fill.clear (); + if (root_trie->first_child) { + qWarning ("Trie not empty"); + dumpTrie (); + } else { + delete root_trie; + root_trie = 0; + } +} + +void KMPlayer::dumpTrie () { + dump (root_trie, 0); +} + +#ifdef TEST_TRIE +// g++ triestring.cpp -o triestring -I$QTDIR/include -L$QTDIR/lib -lqt-mt -g -DTEST_TRIE + +int main (int, char **) { + StringPool::init(); + { + TrieString s1; + TrieString s1_1(QString ("region")); + s1 = s1_1; + TrieString s2 (QString ("regionName")); + TrieString s3 (QString ("regPoint")); + TrieString s4 (QString ("regAlign")); + TrieString s6 (QString ("freeze")); + TrieString s7 (QString ("fit")); + { + TrieString s7_1 (QString ("fit")); + TrieString s5 (QString ("fill")); + dump (root_trie, 0); + } + dump (root_trie, 0); + TrieString s5 (QString ("fill")); + TrieString s8 (QString ("fontPtSize")); + TrieString s9 (QString ("fontSize")); + TrieString s10 (QString ("fontFace")); + TrieString s11 (QString ("fontColor")); + TrieString s12 (QString ("hAlign")); + TrieString s13 (QString ("region")); + TrieString s14 (QString ("ref")); + TrieString s15 (QString ("head")); + dump (root_trie, 0); + QString qs1 = s1.toString (); + QString qs2 = s2.toString (); + printf ("%s\n%s\n", qs1.ascii(), qs2.ascii()); + printf("equal %s %s %d\n", qs2.ascii(), "regionName", s2 == "regionName"); + printf("equal %s %s %d\n", qs2.ascii(), "zegionName", s2 == "zegionName"); + printf("equal %s %s %d\n", qs2.ascii(), "reqionName", s2 == "reqionName"); + printf("equal %s %s %d\n", qs2.ascii(), "regiinName", s2 == "regiinName"); + printf("equal %s %s %d\n", qs2.ascii(), "regionNeme", s2 == "regionNeme"); + printf("%s < %s %d\n", qs2.ascii(), "regionName", s2 < TrieString("regionName")); + printf("%s < %s %d\n", qs2.ascii(), "zegion", s2 < TrieString("zegion")); + printf("%s < %s %d\n", qs2.ascii(), "req", s2 < TrieString("req")); + printf("%s < %s %d\n", qs2.ascii(), "regiinName", s2 < TrieString("regiinName")); + printf("%s < %s %d\n", qs2.ascii(), "regionNeme", s2 < TrieString("regionNeme")); + printf("%s startsWith %s %d\n", s1.toString().ascii(), "region", s1.startsWith ("region")); + printf("%s startsWith %s %d\n", qs2.ascii(), "region", s2.startsWith ("region")); + printf("%s startsWith %s %d\n", qs2.ascii(), "regi", s2.startsWith ("regi")); + printf("%s startsWith %s %d\n", qs2.ascii(), "regian", s2.startsWith ("regian")); + printf("%s startsWith %s %d\n", qs2.ascii(), "regio", s2.startsWith ("regio")); + printf("%s startsWith %s %d\n", qs2.ascii(), "zegio", s2.startsWith ("zegio")); + printf("%s startsWith %s %d\n", qs2.ascii(), "r", s2.startsWith ("r")); + printf("%s startsWith %s %d\n", qs2.ascii(), "q", s2.startsWith ("q")); + TrieString fnt ("font"); + printf("%s startsWith %s %d\n", s8.toString().ascii(), fnt.toString().ascii(), s8.startsWith(fnt)); + printf("%s startsWith %s %d\n", s8.toString().ascii(), s14.toString().ascii(), s8.startsWith(s14)); + } + dump (root_trie, 0); + StringPool::reset(); + return 0; +} +#endif diff --git a/src/triestring.h b/src/triestring.h new file mode 100644 index 0000000..84916d4 --- /dev/null +++ b/src/triestring.h @@ -0,0 +1,103 @@ +/** + This file belong to the KMPlayer project, a movie player plugin for Konqueror + Copyright (C) 2007 Koos Vriezen <[email protected]> + + 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 +**/ + +#ifndef _TRIE_STRING_H_ +#define _TRIE_STRING_H_ + +#include <qstring.h> + +namespace KMPlayer { + +class TrieNode; + +class KMPLAYER_EXPORT TrieString { + TrieNode * node; + friend bool operator == (const TrieString & s1, const TrieString & s2); + friend bool operator == (const TrieString & s, const char * utf8); + friend bool operator == (const char * utf8, const TrieString & s); + friend bool operator != (const TrieString & s1, const TrieString & s2); +public: + TrieString (); + TrieString (const QString & s); + TrieString (const char * utf8); + TrieString (const TrieString & s); + ~TrieString (); + + QString toString () const; + bool isNull () const; + void clear (); + bool startsWith (const TrieString & s) const; + bool startsWith (const char * str) const; + TrieString & operator = (const TrieString & s); + TrieString & operator = (const char * utf8); + bool operator < (const TrieString & s) const; +}; + +inline TrieString::TrieString () : node (0L) {} + +class KMPLAYER_EXPORT StringPool { +public: + static void init(); + static void reset(); + + static TrieString attr_id; + static TrieString attr_name; + static TrieString attr_src; + static TrieString attr_url; + static TrieString attr_href; + static TrieString attr_width; + static TrieString attr_height; + static TrieString attr_top; + static TrieString attr_left; + static TrieString attr_bottom; + static TrieString attr_right; + static TrieString attr_title; + static TrieString attr_begin; + static TrieString attr_dur; + static TrieString attr_end; + static TrieString attr_region; + static TrieString attr_target; + static TrieString attr_type; + static TrieString attr_value; + static TrieString attr_fill; +}; + +inline bool TrieString::isNull () const { + return !node; +} + +inline bool operator == (const TrieString & s1, const TrieString & s2) { + return s1.node == s2.node; +} + +bool operator == (const TrieString & s, const char * utf8); + +inline bool operator == (const char * utf8, const TrieString & s) { + return s == utf8; +} + +inline bool operator != (const TrieString & s1, const TrieString & s2) { + return s1.node != s2.node; +} + +void dumpTrie (); + +} // namespace + +#endif // _TRIE_STRING_H_ diff --git a/src/viewarea.cpp b/src/viewarea.cpp new file mode 100644 index 0000000..de384d7 --- /dev/null +++ b/src/viewarea.cpp @@ -0,0 +1,1691 @@ +/** + This file belong to the KMPlayer project, a movie player plugin for Konqueror + Copyright (C) 2007 Koos Vriezen <[email protected]> + + 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.h> + +#include <stdlib.h> +#include <math.h> + +#include <qapplication.h> +#include <qwidgetstack.h> +#include <qslider.h> +#include <qcursor.h> +#include <qimage.h> +#include <qmap.h> + +#include <kactioncollection.h> +#include <kstaticdeleter.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kshortcut.h> +#include <klocale.h> +#include <kdebug.h> + +#include "kmplayerview.h" +#include "kmplayercontrolpanel.h" +#include "playlistview.h" +#include "viewarea.h" +#ifdef HAVE_CAIRO +# include <cairo-xlib.h> +# include <cairo-xlib-xrender.h> +#endif +#include "kmplayer_smil.h" +#include "kmplayer_rp.h" + +using namespace KMPlayer; + +extern const char * normal_window_xpm[]; +extern const char * playlist_xpm[]; + +//------------------------------------------------------------------------- + +namespace KMPlayer { + typedef QMap <QString, ImageDataPtrW> ImageDataMap; + static KStaticDeleter <ImageDataMap> imageCacheDeleter; + static ImageDataMap * image_data_map; +} + +ImageData::ImageData( const QString & img) : + image (0L), + url (img) { + //if (img.isEmpty ()) + // //kdDebug() << "New ImageData for " << this << endl; + //else + // //kdDebug() << "New ImageData for " << img << endl; + } + +ImageData::~ImageData() { + if (!url.isEmpty ()) + image_data_map->erase (url); + delete image; +} + +#ifdef HAVE_CAIRO +static void copyImage (Surface *s, int w, int h, QImage *img, cairo_surface_t *similar) { + int iw = img->width (); + int ih = img->height (); + + if (img->depth () < 24) { + QImage qi = img->convertDepth (32, 0); + *img = qi; + } + cairo_surface_t *sf = cairo_image_surface_create_for_data ( + img->bits (), + img->hasAlphaBuffer () ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, + iw, ih, img->bytesPerLine ()); + cairo_pattern_t *img_pat = cairo_pattern_create_for_surface (sf); + cairo_pattern_set_extend (img_pat, CAIRO_EXTEND_NONE); + if (w != iw && h != ih) { + cairo_matrix_t mat; + cairo_matrix_init_scale (&mat, 1.0 * iw/w, 1.0 * ih/h); + cairo_pattern_set_matrix (img_pat, &mat); + } + if (!s->surface) + s->surface = cairo_surface_create_similar (similar, + img->hasAlphaBuffer () ? + CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR, w, h); + cairo_t *cr = cairo_create (s->surface); + cairo_set_source (cr, img_pat); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_pattern_destroy (img_pat); + cairo_surface_destroy (sf); +} +#endif + +bool CachedImage::isEmpty () { + return !data || !data->image; +} + +void CachedImage::setUrl (const QString & url) { + if (url.isEmpty ()) { + data = ImageDataPtr (new ImageData (url)); + } else { + ImageDataMap::iterator i = image_data_map->find (url); + if (i == image_data_map->end ()) { + data = ImageDataPtr (new ImageData (url)); + image_data_map->insert (url, ImageDataPtrW (data)); + } else { + ImageDataPtr safe = i.data (); + data = safe; + } + } +} + +//------------------------------------------------------------------------- + +namespace KMPlayer { + +class KMPLAYER_NO_EXPORT ViewSurface : public Surface { +public: + ViewSurface (ViewArea * widget); + ViewSurface (ViewArea * widget, NodePtr owner, const SRect & rect); + ~ViewSurface (); + + void clear () { m_first_child = 0L; } + + SurfacePtr createSurface (NodePtr owner, const SRect & rect); + IRect toScreen (Single x, Single y, Single w, Single h); + void resize (const SRect & rect); + void repaint (); + void repaint (const SRect &rect); + void video (); + + NodePtrW current_video; + ViewArea * view_widget; +}; + +} // namespace + +KDE_NO_CDTOR_EXPORT ViewSurface::ViewSurface (ViewArea * widget) + : Surface (NULL, SRect (0, 0, widget->width (), widget->height ())), + view_widget (widget) +{} + +KDE_NO_CDTOR_EXPORT +ViewSurface::ViewSurface (ViewArea * widget, NodePtr owner, const SRect & rect) + : Surface (owner, rect), view_widget (widget) {} + +KDE_NO_CDTOR_EXPORT ViewSurface::~ViewSurface() { + //kdDebug() << "~ViewSurface" << endl; +} + +SurfacePtr ViewSurface::createSurface (NodePtr owner, const SRect & rect) { + SurfacePtr surface = new ViewSurface (view_widget, owner, rect); + appendChild (surface); + return surface; +} + +KDE_NO_EXPORT void ViewSurface::resize (const SRect &r) { + bounds = r; +#ifdef HAVE_CAIRO + if (surface) + cairo_xlib_surface_set_size (surface, (int)r.width(), (int)r.height ()); +#endif + /*if (rect == nrect) + ;//return; + SRect pr = rect.unite (nrect); // for repaint + rect = nrect;*/ +} + +KDE_NO_EXPORT IRect ViewSurface::toScreen (Single x, Single y, Single w, Single h) { + Matrix matrix (0, 0, xscale, yscale); + matrix.translate (bounds.x (), bounds.y ()); + for (SurfacePtr s = parentNode(); s; s = s->parentNode()) { + matrix.transform(Matrix (0, 0, s->xscale, s->yscale)); + matrix.translate (s->bounds.x (), s->bounds.y ()); + } + matrix.getXYWH (x, y, w, h); + return IRect (x, y, w, h); +} + +KDE_NO_EXPORT +void ViewSurface::repaint (const SRect &r) { + markDirty (); + view_widget->scheduleRepaint (toScreen (r.x (), r.y (), r.width (), r.height ())); + //kdDebug() << "Surface::repaint x:" << (int)x << " y:" << (int)y << " w:" << (int)w << " h:" << (int)h << endl; +} + +KDE_NO_EXPORT +void ViewSurface::repaint () { + markDirty (); + view_widget->scheduleRepaint (toScreen (0, 0, bounds.width (), bounds.height ())); +} + +KDE_NO_EXPORT void ViewSurface::video () { + view_widget->setAudioVideoNode (node); + kdDebug() << "Surface::video:" << background_color << " " << (background_color & 0xff000000) << endl; + xscale = yscale = 1; // either scale width/heigt or use bounds + view_widget->setAudioVideoGeometry (toScreen (0, 0, bounds.width(), bounds.height ()), + (background_color & 0xff000000 ? &background_color : 0)); +} + +//------------------------------------------------------------------------- + +#ifdef HAVE_CAIRO + +static cairo_surface_t * cairoCreateSurface (Window id, int w, int h) { + Display * display = qt_xdisplay (); + return cairo_xlib_surface_create (display, id, + DefaultVisual (display, DefaultScreen (display)), w, h); + /*return cairo_xlib_surface_create_with_xrender_format ( + qt_xdisplay (), + id, + DefaultScreenOfDisplay (qt_xdisplay ()), + XRenderFindVisualFormat (qt_xdisplay (), + DefaultVisual (qt_xdisplay (), + DefaultScreen (qt_xdisplay ()))), + w, h);*/ +} + +# 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) + +class KMPLAYER_NO_EXPORT CairoPaintVisitor : public Visitor { + IRect clip; + cairo_surface_t * cairo_surface; + Matrix matrix; + // stack vars need for transitions + SMIL::MediaType *cur_media; + cairo_pattern_t * cur_pat; + cairo_matrix_t cur_mat; + float opacity; + bool toplevel; + + void traverseRegion (SMIL::RegionBase * reg); + void updateExternal (SMIL::MediaType *av, SurfacePtr s); + void paint(SMIL::MediaType *, Surface *, int x, int y, const IRect &); +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 * n); + void visit (SMIL::Layout *); + void visit (SMIL::Region *); + void visit (SMIL::Transition *); + void visit (SMIL::ImageMediaType *); + void visit (SMIL::TextMediaType *); + void visit (SMIL::Brush *); + void visit (SMIL::RefMediaType *); + void visit (SMIL::AVMediaType *); + 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) + : clip (rect), cairo_surface (cs), matrix (m), toplevel (top) { + cr = cairo_create (cs); + if (toplevel) { + cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h); + cairo_clip (cr); + //cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + 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.w, rect.h); + cairo_fill (cr); + } else { + cairo_save (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h); + cairo_fill (cr); + cairo_restore (cr); + } +} + +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) { + kdWarning() << "Paint called on " << n->nodeName() << endl; +} + +KDE_NO_EXPORT void CairoPaintVisitor::traverseRegion (SMIL::RegionBase * reg) { + // next visit listeners + NodeRefListPtr nl = reg->listeners (mediatype_attached); + if (nl) { + for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) + if (c->data) + c->data->accept (this); + } + // finally visit children, accounting for z-order FIXME optimize + NodeRefList sorted; + for (NodePtr n = reg->firstChild (); n; n = n->nextSibling ()) { + if (n->id != SMIL::id_node_region) + continue; + SMIL::Region * r = static_cast <SMIL::Region *> (n.ptr ()); + NodeRefItemPtr rn = sorted.first (); + for (; rn; rn = rn->nextSibling ()) + if (r->z_order < convertNode <SMIL::Region> (rn->data)->z_order) { + sorted.insertBefore (new NodeRefItem (n), rn); + break; + } + if (!rn) + sorted.append (new NodeRefItem (n)); + } + for (NodeRefItemPtr r = sorted.first (); r; r = r->nextSibling ()) + r->data->accept (this); +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Layout * reg) { + //kdDebug() << "Visit " << reg->nodeName() << endl; + SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (reg->rootLayout); + if (reg->surface () && rb) { + //cairo_save (cr); + Matrix m = matrix; + + SRect rect = reg->region_surface->bounds; + Single x, y, w = rect.width(), h = rect.height(); + matrix.getXYWH (x, y, w, h); + + IRect clip_save = clip; + clip = clip.intersect (IRect (x, y, w, h)); + + rb->region_surface = reg->region_surface; + rb->region_surface->background_color = rb->background_color; + + if (reg->region_surface->background_color & 0xff000000) { + CAIRO_SET_SOURCE_RGB (cr, reg->region_surface->background_color); + cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h); + cairo_fill (cr); + } + //cairo_rectangle (cr, xoff, yoff, w, h); + //cairo_clip (cr); + + matrix = Matrix (0, 0, reg->region_surface->xscale, reg->region_surface->yscale); + matrix.transform (m); + traverseRegion (reg); + //cairo_restore (cr); + matrix = m; + clip = clip_save; + + rb->region_surface = 0L; + } +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Region * reg) { + Surface *s = reg->surface (); + if (s) { + SRect rect = s->bounds; + + Matrix m = matrix; + Single x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height(); + matrix.getXYWH (x, y, w, h); + if (clip.intersect (IRect (x, y, w, h)).isEmpty ()) + return; + matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0); + matrix.transform (m); + IRect clip_save = clip; + clip = clip.intersect (IRect (x, y, w, h)); + cairo_save (cr); + if ((SMIL::RegionBase::ShowAlways == reg->show_background || + reg->m_AttachedMediaTypes->first ()) && + (s->background_color & 0xff000000 || + !reg->cached_img.isEmpty ())) { + cairo_save (cr); + if (s->background_color & 0xff000000) { + CAIRO_SET_SOURCE_RGB (cr, s->background_color); + cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h); + cairo_fill (cr); + } + if (!reg->cached_img.isEmpty ()) { + Single x1, y1; + Single w = reg->cached_img.data->image->width (); + Single h = reg->cached_img.data->image->height(); + matrix.getXYWH (x1, y1, w, h); + if (!s->surface) + copyImage (s, w, h, reg->cached_img.data->image, cairo_surface); + 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, (int) -x, (int) -y); + cairo_pattern_set_matrix (pat, &mat); + cairo_set_source (cr, pat); + cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h); + cairo_fill (cr); + cairo_pattern_destroy (pat); + } + cairo_restore (cr); + } + traverseRegion (reg); + cairo_restore (cr); + matrix = m; + clip = clip_save; + } +} + +#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_media->trans_step / cur_media->trans_steps; + if (cur_media->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.w, clip.h); + 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.h); + rect = IRect (clip.x, clip.y + dy, clip.w, clip.h - dy); + } else { + rect = IRect (clip.x, clip.y, clip.w, (int) (perc * clip.h)); + } + } else { + if (SMIL::Transition::dir_reverse == trans->direction) { + int dx = (int) ((1.0 - perc) * clip.w); + rect = IRect (clip.x + dx, clip.y, clip.w - dx, clip.h); + } else { + rect = IRect (clip.x, clip.y, (int) (perc * clip.w), clip.h); + } + } + cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h); + 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.h); + else if (SMIL::Transition::SubFromRight == trans->sub_type) + dx = (int) ((1.0 - perc) * clip.w); + else if (SMIL::Transition::SubFromBottom == trans->sub_type) + dy = (int) ((1.0 - perc) * clip.h); + else //if (SMIL::Transition::SubFromLeft == trans->sub_type) + dx = -(int) ((1.0 - perc) * clip.w); + cairo_matrix_translate (&cur_mat, -dx, -dy); + IRect rect = clip.intersect (IRect (clip.x + dx, clip.y + dy, + clip.w - dx, clip.h - dy)); + cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h); + 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.w, clip.h); + cairo_clip (cr); + int dx = (int) (perc * clip.w); + int dy = (int) (perc * clip.h); + int mx = clip.x + clip.w/2; + int my = clip.y + clip.h/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.w); + int dy = (int) (0.5 * (1 - perc) * clip.h); + cairo_rectangle (cr, clip.x + dx, clip.y + dy, + clip.w - 2 * dx, clip.h -2 * dy); + } + } else if (SMIL::Transition::ClockWipe == trans->type) { + cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h); + cairo_clip (cr); + int mx = clip.x + clip.w/2; + int my = clip.y + clip.h/2; + cairo_new_path (cr); + cairo_move_to (cr, mx, my); + float hw = 1.0 * clip.w/2; + float hh = 1.0 * clip.h/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.w, clip.h); + cairo_clip (cr); + int mx = clip.x + clip.w/2; + int my = clip.y + clip.h/2; + cairo_new_path (cr); + cairo_move_to (cr, mx, my); + float hw = 1.0 * clip.w/2; + float hh = 1.0 * clip.h/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.w, clip.h); + cairo_clip (cr); + int mx = clip.x + clip.w/2; + int my = clip.y + clip.h/2; + float hw = (double) clip.w/2; + float hh = (double) clip.h/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::visit (SMIL::RefMediaType *ref) { + Surface *s = ref->surface (); + if (s) { + if (ref->external_tree) + updateExternal (ref, s); + else if (ref->needsVideoWidget ()) + s->video (); + } +} + +KDE_NO_EXPORT void CairoPaintVisitor::paint (SMIL::MediaType *mt, Surface *s, + int x, int y, const IRect &rect) { + cairo_save (cr); + opacity = 1.0; + cairo_matrix_init_translate (&cur_mat, -x, -y); + cur_pat = cairo_pattern_create_for_surface (s->surface); + if (mt->active_trans) { + IRect clip_save = clip; + clip = rect; + cur_media = mt; + mt->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.w, rect.h); + } + opacity *= mt->opacity / 100.0; + if (opacity < 0.99) { + cairo_clip (cr); + cairo_paint_with_alpha (cr, opacity); + } else { + cairo_fill (cr); + } + cairo_pattern_destroy (cur_pat); + cairo_restore (cr); +} + +KDE_NO_EXPORT +void CairoPaintVisitor::updateExternal (SMIL::MediaType *av, SurfacePtr s) { + SRect rect = s->bounds; + Single x = rect.x (); + Single y = rect.y (); + Single w = rect.width(); + Single h = rect.height(); + matrix.getXYWH (x, y, w, h); + IRect clip_rect = clip.intersect (IRect (x, y, w, h)); + if (!clip_rect.isValid ()) + return; + if (!s->surface || s->dirty) { + Matrix m = matrix; + m.translate (-x, -y); + IRect r (clip_rect.x - (int) x - 1, clip_rect.y - (int) y - 1, + clip_rect.w + 3, clip_rect.h + 3); + if (!s->surface) { + s->surface = cairo_surface_create_similar (cairo_surface, + CAIRO_CONTENT_COLOR_ALPHA, (int) w, (int) h); + r = IRect (0, 0, w, h); + } + CairoPaintVisitor visitor (s->surface, m, r); + av->external_tree->accept (&visitor); + s->dirty = false; + } + paint (av, s.ptr (), x, y, clip_rect); +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::AVMediaType *av) { + Surface *s = av->surface (); + if (s) { + if (av->external_tree) + updateExternal (av, s); + else if (av->needsVideoWidget ()) + s->video (); + } +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::ImageMediaType * img) { + //kdDebug() << "Visit " << img->nodeName() << " " << img->src << endl; + Surface *s = img->surface (); + if (!s) + return; + if (img->external_tree) { + updateExternal (img, s); + return; + } + ImageRuntime * ir = static_cast <ImageRuntime *> (img->runtime ()); + ImageData * id = ir->cached_img.data.ptr (); + if (!id || !id->image || img->width <= 0 || img->height <= 0) { + s->remove(); + return; + } + SRect rect = s->bounds; + Single x = rect.x (); + Single y = rect.y (); + Single w = rect.width(); + Single h = rect.height(); + matrix.getXYWH (x, y, w, h); + IRect clip_rect = clip.intersect (IRect (x, y, w, h)); + if (clip_rect.isEmpty ()) + return; + if (!s->surface || s->dirty) + copyImage (s, w, h, id->image, cairo_surface); + paint (img, s, x, y, clip_rect); + s->dirty = false; +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::TextMediaType * txt) { + TextRuntime * td = static_cast <TextRuntime *> (txt->runtime ()); + Surface *s = txt->surface (); + //kdDebug() << "Visit " << txt->nodeName() << " " << td->text << endl; + if (!s) + return; + SRect rect = s->bounds; + Single x = rect.x (), y = rect.y(), w = rect.width(), h = rect.height(); + matrix.getXYWH (x, y, w, h); + if (!s->surface) { + //kdDebug() << "new txt surface " << td->text << endl; + /* QTextEdit * edit = new QTextEdit; + edit->setReadOnly (true); + edit->setHScrollBarMode (QScrollView::AlwaysOff); + edit->setVScrollBarMode (QScrollView::AlwaysOff); + edit->setFrameShape (QFrame::NoFrame); + edit->setFrameShadow (QFrame::Plain); + edit->setGeometry (0, 0, w, h); + if (edit->length () == 0) + edit->setText (text); + if (w0 > 0) + font.setPointSize (int (1.0 * w * font_size / w0)); + edit->setFont (font); + QRect rect = p.clipRegion (QPainter::CoordPainter).boundingRect (); + rect = rect.intersect (QRect (xoff, yoff, w, h)); + QPixmap pix = QPixmap::grabWidget (edit, rect.x () - (int) xoff, + rect.y () - (int) yoff, rect.width (), rect.height ());*/ + + float scale = 1.0 * w / rect.width (); // TODO: make an image + cairo_set_font_size (cr, scale * td->font_size); + cairo_font_extents_t txt_fnt; + cairo_font_extents (cr, &txt_fnt); + QString str = td->text; + struct Line { + Line (const QString & ln) : txt (ln), next(0) {} + QString txt; + cairo_text_extents_t txt_ext; + Single xoff; + Line * next; + } *lines = 0, *last_line = 0; + Single y1 = y; + Single max_width; + int line_count = 0; + Single min_xoff = w; + while (!str.isEmpty ()) { + int len = str.find (QChar ('\n')); + bool skip_cr = false; + if (len > 1 && str[len-1] == QChar ('\r')) { + --len; + skip_cr = true; + } + QString para = len > -1 ? str.left (len) : str; + Line * line = new Line (para); + ++line_count; + if (!lines) + lines = line; + else + last_line->next = line; + last_line = line; + int ppos = 0; + while (true) { + cairo_text_extents (cr, line->txt.utf8 ().data (), &line->txt_ext); + float frag = line->txt_ext.width > 0.1 + ? w / line->txt_ext.width : 1.1; + if (frag < 1.0) { + int br_pos = int (line->txt.length () * frag); //educated guess + while (br_pos > 0) { + line->txt.truncate (br_pos); + br_pos = line->txt.findRev (QChar (' ')); + if (br_pos < 1) + break; + line->txt.truncate (br_pos); + cairo_text_extents (cr, line->txt.utf8 ().data (), &line->txt_ext); + if (line->txt_ext.width < (double)w) + break; + } + } + if (line->txt_ext.width > (double)max_width) + max_width = line->txt_ext.width; + + if (td->halign == TextRuntime::align_center) + line->xoff = (w - Single (line->txt_ext.width)) / 2; + else if (td->halign == TextRuntime::align_right) + line->xoff = w - Single (line->txt_ext.width); + if (line->xoff < min_xoff) + min_xoff = line->xoff; + + y1 += Single (txt_fnt.height); + ppos += line->txt.length () + 1; + if (ppos >= para.length ()) + break; + + line->next = new Line (para.mid (ppos)); + ++line_count; + line = line->next; + last_line = line; + } + if (len < 0) + break; + str = str.mid (len + (skip_cr ? 2 : 1)); + } + // new coord in screen space + x += min_xoff; + w = (double)max_width + txt_fnt.max_x_advance / 2; + h = y1 - y /*txt_fnt.height + txt_fnt.descent*/; + + s->surface = cairo_surface_create_similar (cairo_surface, + CAIRO_CONTENT_COLOR, (int) w, (int) h); + cairo_t * cr_txt = cairo_create (s->surface); + cairo_set_font_size (cr_txt, scale * td->font_size); + if (td->bg_opacity) { // TODO real alpha + CAIRO_SET_SOURCE_RGB (cr_txt, td->background_color); + cairo_paint (cr_txt); + } + CAIRO_SET_SOURCE_RGB (cr_txt, td->font_color); + y1 = 0; + while (lines) { + Line * line = lines; + line->xoff += Single (txt_fnt.max_x_advance / 4); + cairo_move_to (cr_txt, line->xoff - min_xoff, y1 + Single (txt_fnt.ascent)); + cairo_show_text (cr_txt, line->txt.utf8 ().data ()); + y1 += Single (txt_fnt.height); + lines = lines->next; + delete line; + } + //cairo_stroke (cr); + cairo_destroy (cr_txt); + + // update bounds rect + Single sx = x, sy = y, sw = w, sh = h; + matrix.invXYWH (sx, sy, sw, sh); + txt->width = sw; + txt->height = sh; + s->bounds = txt->calculateBounds (); + + // update coord. for painting below + x = s->bounds.x (); + y = s->bounds.y(); + w = s->bounds.width(); + h = s->bounds.height(); + matrix.getXYWH (x, y, w, h); + } + IRect clip_rect = clip.intersect (IRect (x, y, w, h)); + if (!clip_rect.isEmpty ()) + paint (txt, s, x, y, clip_rect); + s->dirty = false; +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Brush * brush) { + //kdDebug() << "Visit " << brush->nodeName() << endl; + Surface *s = brush->surface (); + if (s) { + cairo_save (cr); + opacity = 1.0; + SRect rect = s->bounds; + Single x, y, w = rect.width(), h = rect.height(); + matrix.getXYWH (x, y, w, h); + unsigned int color = QColor (brush->param ("color")).rgb (); + if (brush->active_trans) { + cur_media = brush; + cur_pat = NULL; + brush->active_trans->accept (this); + } else { + cairo_rectangle (cr, (int) x, (int) y, (int) w, (int) h); + } + opacity *= brush->opacity / 100.0; + if (opacity < 0.99) + 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); + s->dirty = false; + cairo_restore (cr); + } +} + +KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Imfl * imfl) { + if (imfl->surface ()) { + cairo_save (cr); + Matrix m = matrix; + Single x, y; + Single w = imfl->rp_surface->bounds.width(); + Single h = imfl->rp_surface->bounds.height(); + matrix.getXYWH (x, y, w, h); + cairo_rectangle (cr, x, y, w, h); + //cairo_clip (cr); + cairo_translate (cr, x, y); + cairo_scale (cr, w/imfl->width, h/imfl->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<RP::TimingsBase>(n); + switch (n->id) { + case RP::id_node_viewchange: + if (!(int)tb->srcw) + tb->srcw = imfl->width; + if (!(int)tb->srch) + tb->srch = imfl->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->width; + if (!(int)tb->h) + tb->h = imfl->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) { + //kdDebug() << "Visit " << fi->nodeName() << endl; + 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) { + //kdDebug() << "Visit " << fi->nodeName() << endl; + if (fi->target && fi->target->id == RP::id_node_image) { + RP::Image *img = convertNode <RP::Image> (fi->target); + if (img->surface ()) { + Single sx = fi->srcx, sy = fi->srcy, sw = fi->srcw, sh = fi->srch; + if (!(int)sw) + sw = img->width; + if (!(int)sh) + sh = img->height; + if ((int)fi->w && (int)fi->h && (int)sw && (int)sh) { + if (!img->img_surface->surface) + copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, 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) { + //kdDebug() << "Visit " << fo->nodeName() << endl; + 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) { + //kdDebug() << "Visit " << cf->nodeName() << endl; + if (cf->target && cf->target->id == RP::id_node_image) { + RP::Image *img = convertNode <RP::Image> (cf->target); + if (img->surface ()) { + Single sx = cf->srcx, sy = cf->srcy, sw = cf->srcw, sh = cf->srch; + if (!(int)sw) + sw = img->width; + if (!(int)sh) + sh = img->height; + if ((int)cf->w && (int)cf->h && (int)sw && (int)sh) { + if (!img->img_surface->surface) + copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, 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) { + //kdDebug() << "Visit " << wipe->nodeName() << endl; + if (wipe->target && wipe->target->id == RP::id_node_image) { + RP::Image *img = convertNode <RP::Image> (wipe->target); + if (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->width; + if (!(int)sh) + sh = img->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) + copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, 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) { + //kdDebug() << "Visit " << vc->nodeName() << endl; + 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 { + Matrix matrix; + NodePtr node; + unsigned int event; + int x, y; + bool handled; + bool bubble_up; +public: + MouseVisitor (unsigned int evt, int x, int y); + KDE_NO_CDTOR_EXPORT ~MouseVisitor () {} + using Visitor::visit; + void visit (Node * n); + void visit (SMIL::Layout *); + void visit (SMIL::Region *); + void visit (SMIL::TimedMrl * n); + void visit (SMIL::MediaType * n); + void visit (SMIL::Anchor *); + void visit (SMIL::Area *); + QCursor cursor; +}; + +} // namespace + +KDE_NO_CDTOR_EXPORT +MouseVisitor::MouseVisitor (unsigned int evt, int a, int b) + : event (evt), x (a), y (b), handled (false), bubble_up (false) { +} + +KDE_NO_EXPORT void MouseVisitor::visit (Node * n) { + kdDebug () << "Mouse event ignored for " << n->nodeName () << endl; +} + +KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Layout * layout) { + if (layout->surface ()) { + Matrix m = matrix; + SRect rect = layout->region_surface->bounds; + matrix = Matrix (rect.x(), rect.y(), + layout->region_surface->xscale, layout->region_surface->yscale); + matrix.transform (m); + + NodePtr node_save = node; + node = layout; + for (NodePtr r = layout->firstChild (); r; r = r->nextSibling ()) { + if (r->id == SMIL::id_node_region) + r->accept (this); + if (!node->active ()) + break; + } + node = node_save; + + matrix = m; + } +} + +KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Region * region) { + if (region->surface ()) { + SRect rect = region->region_surface->bounds; + Single rx = rect.x(), ry = rect.y(), rw = rect.width(), rh = rect.height(); + matrix.getXYWH (rx, ry, rw, rh); + handled = false; + bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh; + if (!inside && (event == event_pointer_clicked || !region->has_mouse)) + return; + Matrix m = matrix; + matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0); + matrix.transform (m); + bubble_up = false; + + bool child_handled = false; + if (inside) + for (NodePtr r = region->firstChild (); r; r = r->nextSibling ()) { + r->accept (this); + child_handled |= handled; + if (!node->active ()) + break; + } + child_handled &= !bubble_up; + bubble_up = false; + + int saved_event = event; + if (node->active ()) { + bool propagate_listeners = !child_handled; + if (event == event_pointer_moved) { + propagate_listeners = true; // always pass move events + if (region->has_mouse && (!inside || child_handled)) { + region->has_mouse = false; + event = event_outbounds; + } else if (inside && !child_handled && !region->has_mouse) { + region->has_mouse = true; + event = event_inbounds; + } + }// else // event_pointer_clicked + if (propagate_listeners) { + NodeRefListPtr nl = region->listeners ( + event == event_pointer_moved ? mediatype_attached : event); + if (nl) { + for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) { + if (c->data) + c->data->accept (this); + if (!node->active ()) + break; + } + } + } + } + event = saved_event; + handled = inside; + matrix = m; + } +} + +static void followLink (SMIL::LinkingBase * link) { + kdDebug() << "link to " << link->href << " clicked" << endl; + NodePtr n = link; + if (link->href.startsWith ("#")) { + SMIL::Smil * s = SMIL::Smil::findSmilNode (link); + if (s) + s->jump (link->href.mid (1)); + else + kdError() << "In document jumps smil not found" << endl; + } else + for (NodePtr p = link->parentNode (); p; p = p->parentNode ()) { + if (n->mrl () && n->mrl ()->opener == p) { + p->setState (Node::state_deferred); + p->mrl ()->setParam (StringPool::attr_src, link->href, 0L); + p->activate (); + break; + } + n = p; + } +} + +KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Anchor * anchor) { + if (event == event_pointer_moved) + cursor.setShape (Qt::PointingHandCursor); + else if (event == event_pointer_clicked) + followLink (anchor); +} + +KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Area * area) { + NodePtr n = area->parentNode (); + if (n->id >= SMIL::id_node_first_mediatype && + n->id < SMIL::id_node_last_mediatype) { + SMIL::MediaType * mt = convertNode <SMIL::MediaType> (n); + Surface *s = mt->surface (); + if (s) { + SRect rect = s->bounds; + Single x1 = rect.x (), x2 = rect.y (); + Single w = rect.width (), h = rect.height (); + matrix.getXYWH (x1, x2, w, h); + 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 == event_pointer_moved) + cursor.setShape (Qt::PointingHandCursor); + else { + NodeRefListPtr nl = area->listeners (event); + if (nl) + for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) { + if (c->data) + c->data->accept (this); + if (!node->active ()) + return; + } + if (event == event_pointer_clicked && !area->href.isEmpty ()) + followLink (area); + } + } + } +} + +KDE_NO_EXPORT void MouseVisitor::visit (SMIL::TimedMrl * timedmrl) { + timedmrl->runtime ()->processEvent (event); +} + +KDE_NO_EXPORT void MouseVisitor::visit (SMIL::MediaType * mediatype) { + if (mediatype->sensitivity == SMIL::MediaType::sens_transparent) { + bubble_up = true; + return; + } + Surface *s = mediatype->surface (); + if (!s) + return; + if (s->node && s->node.ptr () != mediatype) { + s->node->accept (this); + return; + } + SRect rect = s->bounds; + Single rx = rect.x(), ry = rect.y(), rw = rect.width(), rh = rect.height(); + matrix.getXYWH (rx, ry, rw, rh); + bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh; + if (!inside && event == event_pointer_clicked) + return; // FIXME, also in/outbounds are bounds related + + NodeRefListPtr nl = mediatype->listeners ( + event == event_pointer_moved ? mediatype_attached : event); + if (nl) + for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) { + if (c->data) + c->data->accept (this); + if (!node->active ()) + return; + } + if (event != event_pointer_moved) + visit (static_cast <SMIL::TimedMrl *> (mediatype)); + if (event != event_inbounds && event != event_outbounds) { + SMIL::RegionBase *r=convertNode<SMIL::RegionBase>(mediatype->region_node); + if (r && r->surface () && + r->id != SMIL::id_node_smil && + r->region_surface->node && r != r->region_surface->node.ptr ()) + return r->region_surface->node->accept (this); + } +} + +//----------------------------------------------------------------------------- + +KDE_NO_CDTOR_EXPORT ViewArea::ViewArea (QWidget * parent, View * view) + : QWidget (parent, "kde_kmplayer_viewarea", WResizeNoErase | WRepaintNoErase), + m_parent (parent), + m_view (view), + m_collection (new KActionCollection (this)), + surface (new ViewSurface (this)), + m_mouse_invisible_timer (0), + m_repaint_timer (0), + m_fullscreen_scale (100), + scale_lbl_id (-1), + scale_slider_id (-1), + m_fullscreen (false), + m_minimal (false) { + setEraseColor (QColor (0, 0, 0)); + setAcceptDrops (true); + new KAction (i18n ("Fullscreen"), KShortcut (Qt::Key_F), this, SLOT (accelActivated ()), m_collection, "view_fullscreen_toggle"); + setMouseTracking (true); + if (!image_data_map) + imageCacheDeleter.setObject (image_data_map, new ImageDataMap); +} + +KDE_NO_CDTOR_EXPORT ViewArea::~ViewArea () { +} + +KDE_NO_EXPORT void ViewArea::fullScreen () { + killTimers (); + m_mouse_invisible_timer = m_repaint_timer = 0; + if (m_fullscreen) { + showNormal (); + reparent (m_parent, 0, QPoint (0, 0), true); + static_cast <KDockWidget *> (m_parent)->setWidget (this); + for (unsigned i = 0; i < m_collection->count (); ++i) + m_collection->action (i)->setEnabled (false); + if (scale_lbl_id != -1) { + m_view->controlPanel ()->popupMenu ()->removeItem (scale_lbl_id); + m_view->controlPanel ()->popupMenu ()->removeItem (scale_slider_id); + scale_lbl_id = scale_slider_id = -1; + } + m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (QIconSet (QPixmap (playlist_xpm))); + } else { + m_topwindow_rect = topLevelWidget ()->geometry (); + reparent (0L, 0, qApp->desktop()->screenGeometry(this).topLeft(), true); + showFullScreen (); + for (unsigned i = 0; i < m_collection->count (); ++i) + m_collection->action (i)->setEnabled (true); + QPopupMenu * menu = m_view->controlPanel ()->popupMenu (); + QLabel * lbl = new QLabel (i18n ("Scale:"), menu); + scale_lbl_id = menu->insertItem (lbl, -1, 4); + QSlider * slider = new QSlider (50, 150, 10, m_fullscreen_scale, Qt::Horizontal, menu); + connect (slider, SIGNAL (valueChanged (int)), this, SLOT (scale (int))); + scale_slider_id = menu->insertItem (slider, -1, 5); + m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (QIconSet (QPixmap (normal_window_xpm))); + } + m_fullscreen = !m_fullscreen; + m_view->controlPanel()->popupMenu ()->setItemChecked (ControlPanel::menu_fullscreen, m_fullscreen); + +#ifdef HAVE_CAIRO + if (surface->surface) { + cairo_surface_destroy (surface->surface); + surface->surface = 0L; + } +#endif + if (m_fullscreen) { + m_mouse_invisible_timer = startTimer(MOUSE_INVISIBLE_DELAY); + } else { + if (m_mouse_invisible_timer) { + killTimer (m_mouse_invisible_timer); + m_mouse_invisible_timer = 0; + } + unsetCursor(); + } +} + +void ViewArea::minimalMode () { + m_minimal = !m_minimal; + killTimers (); + 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 ()->button (ControlPanel::button_playlist)->setIconSet (QIconSet (QPixmap (normal_window_xpm))); + } else { + m_view->setControlPanelMode (KMPlayer::View::CP_Show); + m_view->setNoInfoMessages (false); + m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (QIconSet (QPixmap (playlist_xpm))); + } + m_topwindow_rect = topLevelWidget ()->geometry (); +} + +KDE_NO_EXPORT void ViewArea::accelActivated () { + m_view->controlPanel()->popupMenu ()->activateItemAt (m_view->controlPanel()->popupMenu ()->indexOf (ControlPanel::menu_fullscreen)); +} + +KDE_NO_EXPORT void ViewArea::mousePressEvent (QMouseEvent * e) { + if (surface->node) { + MouseVisitor visitor (event_pointer_clicked, e->x(), e->y()); + surface->node->accept (&visitor); + } + e->accept (); +} + +KDE_NO_EXPORT void ViewArea::mouseDoubleClickEvent (QMouseEvent *) { + m_view->fullScreen (); // screensaver stuff +} + +KDE_NO_EXPORT void ViewArea::mouseMoveEvent (QMouseEvent * e) { + if (e->state () == Qt::NoButton) { + int vert_buttons_pos = height () - m_view->statusBarHeight (); + int cp_height = m_view->controlPanel ()->maximumSize ().height (); + m_view->delayedShowButtons (e->y() > vert_buttons_pos-cp_height && + e->y() < vert_buttons_pos); + } + if (surface->node) { + MouseVisitor visitor (event_pointer_moved, e->x(), e->y()); + surface->node->accept (&visitor); + setCursor (visitor.cursor); + } + e->accept (); + mouseMoved (); // for m_mouse_invisible_timer +} + +KDE_NO_EXPORT void ViewArea::syncVisual (const IRect & rect) { +#ifdef HAVE_CAIRO + int ex = rect.x; + if (ex > 0) + ex--; + int ey = rect.y; + if (ey > 0) + ey--; + int ew = rect.w + 2; + int eh = rect.h + 2; + if (!surface->surface) + surface->surface = cairoCreateSurface (winId (), width (), height ()); + if (surface->node && (!video_node || + !convertNode <SMIL::MediaType> (video_node)->needsVideoWidget())) + setAudioVideoGeometry (IRect (), NULL); + CairoPaintVisitor visitor (surface->surface, + Matrix (surface->bounds.x(), surface->bounds.y(), 1.0, 1.0), + IRect (ex, ey, ew, eh), paletteBackgroundColor (), true); + if (surface->node) + surface->node->accept (&visitor); +#else + repaint (QRect(rect.x, rect.y, rect.w, rect.h), false); +#endif + if (m_repaint_timer) { + killTimer (m_repaint_timer); + m_repaint_timer = 0; + } + //XFlush (qt_xdisplay ()); +} + +KDE_NO_EXPORT void ViewArea::paintEvent (QPaintEvent * pe) { +#ifdef HAVE_CAIRO + if (surface->node) + scheduleRepaint (IRect (pe->rect ().x (), pe->rect ().y (), pe->rect ().width (), pe->rect ().height ())); + else +#endif + QWidget::paintEvent (pe); +} + +KDE_NO_EXPORT void ViewArea::scale (int val) { + m_fullscreen_scale = val; + resizeEvent (0L); +} + +KDE_NO_EXPORT void ViewArea::updateSurfaceBounds () { + Single x, y, w = width (), h = height (); + h -= m_view->statusBarHeight (); + h -= m_view->controlPanel ()->isVisible () + ? (m_view->controlPanelMode () == View::CP_Only + ? h + : (Single) m_view->controlPanel()->maximumSize ().height ()) + : Single (0); + surface->resize (SRect (x, y, w, h)); + Mrl *mrl = surface->node ? surface->node->mrl () : NULL; + if (m_view->keepSizeRatio () && + w > 0 && h > 0 && + mrl && mrl->width > 0 && mrl->height > 0) { + double wasp = (double) w / h; + double masp = (double) mrl->width / mrl->height; + if (wasp > masp) { + Single tmp = w; + w = masp * h; + x += (tmp - w) / 2; + } else { + Single tmp = h; + h = Single (w / masp); + y += (tmp - h) / 2; + } + surface->xscale = 1.0 * w / mrl->width; + surface->yscale = 1.0 * h / mrl->height; + } else { + surface->xscale = 1.0; + surface->yscale = 1.0; + } + surface->bounds = SRect (x, y, w, h); + scheduleRepaint (IRect (0, 0, width (), height ())); +} + +KDE_NO_EXPORT void ViewArea::resizeEvent (QResizeEvent *) { + if (!m_view->controlPanel ()) return; + Single x, y, w = width (), h = height (); + Single hsb = m_view->statusBarHeight (); + Single hcp = m_view->controlPanel ()->isVisible () + ? (m_view->controlPanelMode () == View::CP_Only + ? h-hsb + : (Single) m_view->controlPanel()->maximumSize ().height ()) + : Single (0); + Single wws = w; + // move controlpanel over video when autohiding and playing + Single hws = h - (m_view->controlPanelMode () == View::CP_AutoHide && + m_view->widgetStack ()->visibleWidget () == m_view->viewer () + ? Single (0) + : hcp) - hsb; + // now scale the regions and check if video region is already sized + if (surface->node) { + NodePtr n = surface->node; + surface = new ViewSurface (this); + surface->node = n; + } + updateSurfaceBounds (); + + // finally resize controlpanel and video widget + if (m_view->controlPanel ()->isVisible ()) + m_view->controlPanel ()->setGeometry (0, h-hcp-hsb, w, hcp); + if (m_view->statusBar ()->isVisible ()) + m_view->statusBar ()->setGeometry (0, h-hsb, w, hsb); + if (m_fullscreen && wws == w && hws == h) { + wws = wws * m_fullscreen_scale / 100; + hws = hws * m_fullscreen_scale / 100; + x += (w - wws) / 2; + y += (h - hws) / 2; + } + if (!surface->node) + setAudioVideoGeometry (IRect (x, y, wws, hws), 0L); +} + +KDE_NO_EXPORT +void ViewArea::setAudioVideoGeometry (const IRect &rect, unsigned int * bg_color) { + int x = rect.x, y = rect.y, w = rect.w, h = rect.h; + if (m_view->controlPanelMode() == View::CP_Only) { + w = h = 0; + } else if (!surface->node && m_view->keepSizeRatio ()) { // scale video widget inside region + int hfw = m_view->viewer ()->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; + } + } + m_av_geometry = QRect (x, y, w, h); + QRect wrect = m_view->widgetStack ()->geometry (); + if (m_av_geometry != wrect && + !(m_av_geometry.width() <= 0 && + wrect.width() <= 1 && wrect.height() <= 1)) { + m_view->widgetStack ()->setGeometry (x, y, w, h); + wrect.unite (m_av_geometry); + scheduleRepaint (IRect (wrect.x (), wrect.y (), wrect.width (), wrect.height ())); + } + if (bg_color) + if (QColor (QRgb (*bg_color)) != (m_view->viewer ()->paletteBackgroundColor ())) { + m_view->viewer()->setCurrentBackgroundColor (QColor (QRgb (*bg_color))); + scheduleRepaint (IRect (x, y, w, h)); + } +} + +KDE_NO_EXPORT void ViewArea::setAudioVideoNode (NodePtr n) { + video_node = n; +} + +KDE_NO_EXPORT SurfacePtr ViewArea::getSurface (NodePtr node) { + static_cast <ViewSurface *> (surface.ptr ())->clear (); + surface->node = node; + m_view->viewer()->resetBackgroundColor (); + if (node) { + updateSurfaceBounds (); + return surface; + } + scheduleRepaint (IRect (0, 0, width (), height ())); + 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 (10); // 100 per sec should do + } +} + +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 (BlankCursor); + } else if (e->timerId () == m_repaint_timer) { + killTimer (m_repaint_timer); + m_repaint_timer = 0; + //repaint (m_repaint_rect, false); + syncVisual (m_repaint_rect.intersect (IRect (0, 0, width (), height ()))); + } else { + kdError () << "unknown timer " << e->timerId () << " " << m_repaint_timer << endl; + killTimer (e->timerId ()); + } +} + +KDE_NO_EXPORT void ViewArea::closeEvent (QCloseEvent * e) { + //kdDebug () << "closeEvent" << endl; + if (m_fullscreen) { + fullScreen (); + if (!m_parent->topLevelWidget ()->isVisible ()) + m_parent->topLevelWidget ()->show (); + e->ignore (); + } else + QWidget::closeEvent (e); +} + + +#include "viewarea.moc" diff --git a/src/viewarea.h b/src/viewarea.h new file mode 100644 index 0000000..6277b6e --- /dev/null +++ b/src/viewarea.h @@ -0,0 +1,89 @@ +/** + This file belong to the KMPlayer project, a movie player plugin for Konqueror + Copyright (C) 2007 Koos Vriezen <[email protected]> + + 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 +**/ + +#ifndef KMPLAYER_VIEW_AREA_H +#define KMPLAYER_VIEW_AREA_H + +#include <qwidget.h> + +class KActionCollection; + +namespace KMPlayer { + +class View; +class ViewAreaPrivate; + +/* + * The area in which the video widget and controlpanel are laid out + */ +class KMPLAYER_EXPORT ViewArea : public QWidget { + Q_OBJECT +public: + ViewArea (QWidget * parent, View * view); + ~ViewArea (); + KDE_NO_EXPORT bool isFullScreen () const { return m_fullscreen; } + KDE_NO_EXPORT bool isMinimalMode () const { return m_minimal; } + KDE_NO_EXPORT KActionCollection * actionCollection () const { return m_collection; } + KDE_NO_EXPORT QRect topWindowRect () const { return m_topwindow_rect; } + SurfacePtr getSurface (NodePtr node); + void setAudioVideoGeometry (const IRect &rect, unsigned int * bg); + void setAudioVideoNode (NodePtr n); + void mouseMoved (); + void scheduleRepaint (const IRect &rect); + void resizeEvent (QResizeEvent *); + void minimalMode (); +public slots: + void fullScreen (); + void accelActivated (); + void scale (int); +protected: + void showEvent (QShowEvent *); + void mouseMoveEvent (QMouseEvent *); + void mousePressEvent (QMouseEvent *); + void mouseDoubleClickEvent (QMouseEvent *); + void dragEnterEvent (QDragEnterEvent *); + void dropEvent (QDropEvent *); + void contextMenuEvent (QContextMenuEvent * e); + void paintEvent (QPaintEvent *); + void timerEvent (QTimerEvent * e); + void closeEvent (QCloseEvent * e); +private: + void syncVisual (const IRect & rect); + void updateSurfaceBounds (); + ViewAreaPrivate * d; + QWidget * m_parent; + View * m_view; + KActionCollection * m_collection; + SurfacePtr surface; + NodePtrW video_node; + QRect m_av_geometry; + IRect m_repaint_rect; + QRect m_topwindow_rect; + int m_mouse_invisible_timer; + int m_repaint_timer; + int m_fullscreen_scale; + int scale_lbl_id; + int scale_slider_id; + bool m_fullscreen; + bool m_minimal; +}; + +} // namespace KMPlayer + +#endif diff --git a/src/xineplayer.cpp b/src/xineplayer.cpp new file mode 100644 index 0000000..17e6fd2 --- /dev/null +++ b/src/xineplayer.cpp @@ -0,0 +1,1239 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2003 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <config.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <libgen.h> +#include <dcopclient.h> +#include <qcstring.h> +#include <qtimer.h> +#include <qfile.h> +#include <qurl.h> +#include <qthread.h> +#include <qmutex.h> +#include <qdom.h> +#include "kmplayer_backend.h" +#include "kmplayer_callback_stub.h" +#include "kmplayer_callback.h" +#include "xineplayer.h" +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> + +#include <xine.h> +#include <xine/xineutils.h> + +#ifndef XShmGetEventBase +extern int XShmGetEventBase(Display *); +#endif + +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 +typedef struct { + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t input_mode; + uint32_t status; +} MWMHints; + + +static KXinePlayer * xineapp; +static KMPlayer::Callback_stub * callback; +static QMutex mutex (true); + +static xine_t *xine; +static xine_stream_t *stream; +static xine_stream_t *sub_stream; +static xine_video_port_t *vo_port; +static xine_audio_port_t *ao_port; +static xine_post_t *post_plugin; +static xine_event_queue_t *event_queue; +static xine_cfg_entry_t audio_vis_cfg_entry; +static x11_visual_t vis; +static char configfile[2048]; +static Atom quit_atom; + +static Display *display; +static Window wid; +static bool window_created; +static bool xine_verbose; +static bool xine_vverbose; +static bool wants_config; +static bool audio_vis; +static int screen; +static int completion_event; +static int repeat_count; +static int xpos, ypos, width, height; +static int movie_width, movie_height, movie_length, movie_pos; +static int movie_brightness = 32767; +static int movie_contrast = 32767; +static int movie_hue = 32767; +static int movie_saturation = 32767; +static int movie_volume = 32767; +static double pixel_aspect; + +static int running = 0; +static volatile int firstframe = 0; +static const int event_finished = QEvent::User; +static const int event_progress = QEvent::User + 2; +static const int event_url = QEvent::User + 3; +static const int event_size = QEvent::User + 4; +static const int event_title = QEvent::User + 5; +static const int event_video = QEvent::User + 6; +static QString mrl; +static QString sub_mrl; +static QString rec_mrl; +static QString alang, slang; +static QStringList alanglist, slanglist; + +static QString elmentry ("entry"); +static QString elmitem ("item"); +static QString attname ("name"); +static QString atttype ("type"); +static QString attdefault ("DEFAULT"); +static QString attvalue ("value"); +static QString attstart ("START"); +static QString attend ("end"); +static QString valrange ("range"); +static QString valnum ("num"); +static QString valbool ("bool"); +static QString valenum ("enum"); +static QString valstring ("string"); + +extern "C" { + +static void dest_size_cb(void * /*data*/, int /*video_width*/, int /*video_height*/, double /*video_pixel_aspect*/, + int *dest_width, int *dest_height, double *dest_pixel_aspect) { + + *dest_width = width; + *dest_height = height; + *dest_pixel_aspect = pixel_aspect; +} + +static void frame_output_cb(void * /*data*/, int /*video_width*/, int /*video_height*/, + double /*video_pixel_aspect*/, int *dest_x, int *dest_y, + int *dest_width, int *dest_height, + double *dest_pixel_aspect, int *win_x, int *win_y) { + if (running && firstframe) { + firstframe = 0; + int pos; + fprintf(stderr, "first frame\n"); + mutex.lock (); + xine_get_pos_length (stream, 0, &pos, &movie_length); + movie_width = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_WIDTH); + movie_height = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_HEIGHT); + mutex.unlock (); + QApplication::postEvent (xineapp, new XineMovieParamEvent (movie_length, movie_width, movie_height, alanglist, slanglist, true)); + + } + + *dest_x = 0; + *dest_y = 0; + *win_x = xpos; + *win_y = ypos; + *dest_width = width; + *dest_height = height; + *dest_pixel_aspect = pixel_aspect; +} + +static void xine_config_cb (void * /*user_data*/, xine_cfg_entry_t * entry) { + fprintf (stderr, "xine_config_cb %s\n", entry->enum_values[entry->num_value]); + if (!stream) + return; + mutex.lock (); + if (post_plugin) { + xine_post_wire_audio_port (xine_get_audio_source (stream), ao_port); + xine_post_dispose (xine, post_plugin); + post_plugin = 0L; + } + if (audio_vis && strcmp (entry->enum_values[entry->num_value], "none")) { + post_plugin = xine_post_init (xine, entry->enum_values[entry->num_value], 0, &ao_port, &vo_port); + xine_post_wire (xine_get_audio_source (stream), (xine_post_in_t *) xine_post_input (post_plugin, (char *) "audio in")); + } + mutex.unlock (); +} + +static void event_listener(void * /*user_data*/, const xine_event_t *event) { + if (event->stream != stream) + return; // not interested in sub_stream events + switch(event->type) { + case XINE_EVENT_UI_PLAYBACK_FINISHED: + fprintf (stderr, "XINE_EVENT_UI_PLAYBACK_FINISHED\n"); + if (repeat_count-- > 0) + xine_play (stream, 0, 0); + else + QApplication::postEvent (xineapp, new QEvent ((QEvent::Type) event_finished)); + break; + case XINE_EVENT_PROGRESS: + QApplication::postEvent (xineapp, new XineProgressEvent (((xine_progress_data_t *) event->data)->percent)); + break; + case XINE_EVENT_MRL_REFERENCE: + fprintf(stderr, "XINE_EVENT_MRL_REFERENCE %s\n", + ((xine_mrl_reference_data_t*)event->data)->mrl); + QApplication::postEvent (xineapp, new XineURLEvent (QString::fromLocal8Bit (((xine_mrl_reference_data_t*)event->data)->mrl))); + break; + case XINE_EVENT_FRAME_FORMAT_CHANGE: + fprintf (stderr, "XINE_EVENT_FRAME_FORMAT_CHANGE\n"); + break; + case XINE_EVENT_UI_SET_TITLE: + { + xine_ui_data_t * data = (xine_ui_data_t *) event->data; + QApplication::postEvent(xineapp, new XineTitleEvent(data->str)); + fprintf (stderr, "Set title event %s\n", data->str); + } + break; + case XINE_EVENT_UI_CHANNELS_CHANGED: { + fprintf (stderr, "Channel changed event %d\n", firstframe); + mutex.lock (); + int w = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_WIDTH); + int h = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_HEIGHT); + int pos, l, nr; + xine_get_pos_length (stream, 0, &pos, &l); + char * langstr = new char [66]; + alanglist.clear (); + slanglist.clear (); + + nr =xine_get_stream_info(stream,XINE_STREAM_INFO_MAX_AUDIO_CHANNEL); + // if nrch > 25) nrch = 25 + for (int i = 0; i < nr; ++i) { + if (!xine_get_audio_lang (stream, i, langstr)) + continue; + QString ls = QString::fromLocal8Bit (langstr).stripWhiteSpace(); + if (ls.isEmpty ()) + continue; + if (!slang.isEmpty () && alang == ls) + xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, i); + alanglist.push_back (ls); + fprintf (stderr, "alang %s\n", langstr); + } + nr = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL); + // if nrch > 25) nrch = 25 + for (int i = 0; i < nr; ++i) { + if (!xine_get_spu_lang (stream, i, langstr)) + continue; + QString ls = QString::fromLocal8Bit (langstr).stripWhiteSpace(); + if (ls.isEmpty ()) + continue; + if (!slang.isEmpty () && slang == ls) + xine_set_param (stream, XINE_PARAM_SPU_CHANNEL, i); + slanglist.push_back (ls); + fprintf (stderr, "slang %s\n", langstr); + } + delete langstr; + mutex.unlock (); + movie_width = w; + movie_height = h; + movie_length = l; + QApplication::postEvent (xineapp, new XineMovieParamEvent (l, w, h, alanglist, slanglist, firstframe)); + if (running && firstframe) + firstframe = 0; + if (window_created && w > 0 && h > 0) { + XLockDisplay (display); + XResizeWindow (display, wid, movie_width, movie_height); + XFlush (display); + XUnlockDisplay (display); + } + break; + } + case XINE_EVENT_INPUT_MOUSE_MOVE: + break; + default: + fprintf (stderr, "event_listener %d\n", event->type); + + } +} + +} // extern "C" + +using namespace KMPlayer; + +Backend::Backend () + : DCOPObject (QCString ("Backend")) { +} + +Backend::~Backend () {} + +void Backend::setURL (QString url) { + mrl = url; +} + +void Backend::setSubTitleURL (QString url) { + sub_mrl = url; +} + +void Backend::play (int repeat_count) { + xineapp->play (repeat_count); +} + +void Backend::stop () { + QTimer::singleShot (0, xineapp, SLOT (stop ())); +} + +void Backend::pause () { + xineapp->pause (); +} + +void Backend::seek (int pos, bool /*absolute*/) { + xineapp->seek (pos); +} + +void Backend::hue (int h, bool) { + xineapp->hue (65535 * (h + 100) / 200); +} + +void Backend::saturation (int s, bool) { + xineapp->saturation (65535 * (s + 100) / 200); +} + +void Backend::contrast (int c, bool) { + xineapp->contrast (65535 * (c + 100) / 200); +} + +void Backend::brightness (int b, bool) { + xineapp->brightness (65535 * (b + 100) / 200); +} + +void Backend::volume (int v, bool) { + xineapp->volume (v); +} + +void Backend::frequency (int) { +} + +void Backend::setAudioLang (int id, QString al) { + xineapp->setAudioLang (id, al); +} + +void Backend::setSubtitle (int id, QString sl) { + xineapp->setSubtitle (id, sl); +} + +void Backend::quit () { + delete callback; + callback = 0L; + if (running) + stop (); + else + QTimer::singleShot (0, qApp, SLOT (quit ())); +} + +bool updateConfigEntry (const QString & name, const QString & value) { + fprintf (stderr, "%s=%s\n", name.ascii (), (const char *) value.local8Bit ()); + bool changed = false; + xine_cfg_entry_t cfg_entry; + if (!xine_config_lookup_entry (xine, name.ascii (), &cfg_entry)) + return false; + if (cfg_entry.type == XINE_CONFIG_TYPE_STRING || + cfg_entry.type == XINE_CONFIG_TYPE_UNKNOWN) { + changed = strcmp (cfg_entry.str_value, value.ascii ()); + cfg_entry.str_value = (char *) value.ascii (); + } else { + changed = cfg_entry.num_value != value.toInt (); + cfg_entry.num_value = value.toInt (); + } + xine_config_update_entry (xine, &cfg_entry); + return changed; +} + +void Backend::setConfig (QByteArray data) { + QString err; + int line, column; + QDomDocument dom; + if (dom.setContent (data, false, &err, &line, &column)) { + if (dom.childNodes().length() == 1) { + for (QDomNode node = dom.firstChild().firstChild(); + !node.isNull (); + node = node.nextSibling ()) { + QDomNamedNodeMap attr = node.attributes (); + updateConfigEntry (attr.namedItem (attname).nodeValue (), + attr.namedItem (attvalue).nodeValue ()); + } + xine_config_save (xine, configfile); + } else + err = QString ("invalid data"); + } + if (callback) + callback->errorMessage (0, err); +} + +bool Backend::isPlaying () { + mutex.lock (); + bool b = running && + (xine_get_status (stream) == XINE_STATUS_PLAY) && + (xine_get_param (stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE); + mutex.unlock (); + return b; +} + +KXinePlayer::KXinePlayer (int _argc, char ** _argv) + : QApplication (_argc, _argv, false) { +} + +void KXinePlayer::init () { + xpos = 0; + ypos = 0; + width = 320; + height = 200; + + XLockDisplay(display); + if (window_created) + wid = XCreateSimpleWindow(display, XDefaultRootWindow(display), + xpos, ypos, width, height, 1, 0, 0); + XSelectInput (display, wid, + (PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask)); // | SubstructureNotifyMask)); + XWindowAttributes attr; + XGetWindowAttributes(display, wid, &attr); + width = attr.width; + height = attr.height; + if (XShmQueryExtension(display) == True) + completion_event = XShmGetEventBase(display) + ShmCompletion; + else + completion_event = -1; + if (window_created) { + fprintf (stderr, "map %lu\n", wid); + XMapRaised(display, wid); + XSync(display, False); + } + //double d->res_h = 1.0 * DisplayWidth(display, screen) / DisplayWidthMM(display, screen); + //double d->res_v = 1.0 * DisplayHeight(display, screen) / DisplayHeightMM(display, screen); + XUnlockDisplay(display); + vis.display = display; + vis.screen = screen; + vis.d = wid; + vis.dest_size_cb = dest_size_cb; + vis.frame_output_cb = frame_output_cb; + vis.user_data = NULL; + //pixel_aspect = d->res_v / d->res_h; + + //if(fabs(pixel_aspect - 1.0) < 0.01) + pixel_aspect = 1.0; + + const char *const * pp = xine_list_post_plugins_typed (xine, XINE_POST_TYPE_AUDIO_VISUALIZATION); + int i; + for (i = 0; pp[i]; i++); + const char ** options = new const char * [i+2]; + options[0] = "none"; + for (i = 0; pp[i]; i++) + options[i+1] = pp[i]; + options[i+1] = 0L; + xine_config_register_enum (xine, "audio.visualization", 0, (char ** ) options, 0L, 0L, 0, xine_config_cb, 0L); + if (!callback) + QTimer::singleShot (10, this, SLOT (play ())); +} + +KXinePlayer::~KXinePlayer () { + if (window_created) { + XLockDisplay (display); + fprintf (stderr, "unmap %lu\n", wid); + XUnmapWindow (display, wid); + XDestroyWindow(display, wid); + XSync (display, False); + XUnlockDisplay (display); + } + xineapp = 0L; +} + +void getConfigEntries (QByteArray & buf) { + xine_cfg_entry_t entry; + QDomDocument doc; + QDomElement root = doc.createElement (QString ("document")); + for (int i = xine_config_get_first_entry (xine, &entry); + i; + i = xine_config_get_next_entry (xine, &entry)) { + QDomElement elm = doc.createElement (elmentry); + elm.setAttribute (attname, QString (entry.key)); + if (entry.type == XINE_CONFIG_TYPE_STRING || entry.type == XINE_CONFIG_TYPE_UNKNOWN) { + elm.setAttribute (atttype, valstring); + elm.setAttribute (attvalue, QString (entry.str_value)); + } else { + elm.setAttribute (attdefault, QString::number (entry.num_default)); + elm.setAttribute (attvalue, QString::number (entry.num_value)); + switch (entry.type) { + case XINE_CONFIG_TYPE_RANGE: + elm.setAttribute (atttype, valrange); + elm.setAttribute (attstart, QString::number (entry.range_min)); + elm.setAttribute (attend, QString::number (entry.range_max)); + break; + case XINE_CONFIG_TYPE_ENUM: + elm.setAttribute (atttype, valenum); + for (int i = 0; entry.enum_values[i]; i++) { + QDomElement item = doc.createElement (elmitem); + item.setAttribute (attvalue, QString (entry.enum_values[i])); + elm.appendChild (item); + } + break; + case XINE_CONFIG_TYPE_NUM: + elm.setAttribute (atttype, valnum); + break; + case XINE_CONFIG_TYPE_BOOL: + elm.setAttribute (atttype, valbool); + break; + default: + fprintf (stderr, "unhandled config type: %d\n", entry.type); + } + } + if (entry.help) + elm.appendChild (doc.createTextNode (QString::fromUtf8 (entry.help))); + root.appendChild (elm); + } + doc.appendChild (root); + QString exp = doc.toString (); + QCString cexp = exp.utf8 (); + buf.duplicate (cexp); + buf.resize (cexp.length ()); // strip terminating \0 +} + +void KXinePlayer::play (int repeat) { + fprintf (stderr, "play mrl: '%s'\n", (const char *) mrl.local8Bit ()); + mutex.lock (); + repeat_count = repeat; + if (running) { + if (xine_get_status (stream) == XINE_STATUS_PLAY && + xine_get_param (stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) + xine_set_param( stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); + mutex.unlock (); + return; + } + movie_pos = 0; + movie_width = 0; + movie_height = 0; + + if (mrl.startsWith ("cdda://")) + mrl = QString ("cdda:/") + mrl.mid (7); + stream = xine_stream_new (xine, ao_port, vo_port); + event_queue = xine_event_new_queue (stream); + xine_event_create_listener_thread (event_queue, event_listener, NULL); + if (mrl == "cdda:/") { + int nr; + char ** mrls = xine_get_autoplay_mrls (xine, "CD", &nr); + running = 1; + for (int i = 0; i < nr; i++) { + QString m (mrls[i]); + QString title; + if (xine_open (stream, mrls[i])) { + const char * t = xine_get_meta_info (stream, XINE_META_INFO_TITLE); + if (t && t[0]) + title = QString::fromUtf8 (t); + xine_close (stream); + } + if (callback) + callback->subMrl (m, title); + else + printf ("track %s\n", m.utf8 ().data ()); + } + mutex.unlock (); + finished (); + return; + } + + xine_gui_send_vo_data(stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1); + + running = 1; + QString mrlsetup = mrl; + if (!rec_mrl.isEmpty ()) { + char * rm = strdup (rec_mrl.local8Bit ()); + char *bn = basename (rm); + char *dn = dirname (rm); + if (bn) + updateConfigEntry (QString ("media.capture.save_dir"), QString::fromLocal8Bit (dn)); + mrlsetup += QString ("#save:") + QString::fromLocal8Bit (bn); + free (rm); + } + if (!xine_open (stream, (const char *) mrlsetup.local8Bit ())) { + fprintf(stderr, "Unable to open mrl '%s'\n", (const char *) mrl.local8Bit ()); + mutex.unlock (); + finished (); + return; + } + xine_set_param (stream, XINE_PARAM_VO_SATURATION, movie_saturation); + xine_set_param (stream, XINE_PARAM_VO_BRIGHTNESS, movie_brightness); + xine_set_param (stream, XINE_PARAM_VO_CONTRAST, movie_contrast); + xine_set_param (stream, XINE_PARAM_VO_HUE, movie_hue); + + if (!sub_mrl.isEmpty ()) { + fprintf(stderr, "Using subtitles from '%s'\n", (const char *) sub_mrl.local8Bit ()); + sub_stream = xine_stream_new (xine, NULL, vo_port); + if (xine_open (sub_stream, (const char *) sub_mrl.local8Bit ())) { + xine_stream_master_slave (stream, sub_stream, + XINE_MASTER_SLAVE_PLAY | XINE_MASTER_SLAVE_STOP); + } else { + fprintf(stderr, "Unable to open subtitles from '%s'\n", (const char *) sub_mrl.local8Bit ()); + xine_dispose (sub_stream); + sub_stream = 0L; + } + } + if (!xine_play (stream, 0, 0)) { + fprintf(stderr, "Unable to play mrl '%s'\n", (const char *) mrl.local8Bit ()); + mutex.unlock (); + finished (); + return; + } + audio_vis = false; + if (xine_get_stream_info (stream, XINE_STREAM_INFO_HAS_VIDEO)) + QApplication::postEvent(xineapp, new QEvent((QEvent::Type)event_video)); + else + audio_vis = xine_config_lookup_entry + (xine, "audio.visualization", &audio_vis_cfg_entry); + mutex.unlock (); + if (audio_vis) + xine_config_cb (0L, &audio_vis_cfg_entry); + if (callback) + firstframe = 1; +} + +void KXinePlayer::stop () { + if (!running) return; + fprintf(stderr, "stop\n"); + mutex.lock (); + repeat_count = 0; + if (sub_stream) + xine_stop (sub_stream); + xine_stop (stream); + mutex.unlock (); + QTimer::singleShot (10, this, SLOT (postFinished ())); +} + +void KXinePlayer::postFinished () { + QApplication::postEvent (xineapp, new QEvent ((QEvent::Type) event_finished)); +} + +void KXinePlayer::pause () { + if (!running) return; + mutex.lock (); + if (xine_get_status (stream) == XINE_STATUS_PLAY) { + if (xine_get_param (stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) + xine_set_param (stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); + else + xine_set_param (stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); + } + mutex.unlock (); +} + +void KXinePlayer::finished () { + QTimer::singleShot (10, this, SLOT (stop ())); +} + +void KXinePlayer::setAudioLang (int id, const QString & al) { + alang = al; + mutex.lock (); + if (xine_get_status (stream) == XINE_STATUS_PLAY) + xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, id); + mutex.unlock (); +} + +void KXinePlayer::setSubtitle (int id, const QString & sl) { + slang = sl; + mutex.lock (); + if (xine_get_status (stream) == XINE_STATUS_PLAY) + xine_set_param (stream, XINE_PARAM_SPU_CHANNEL, id); + mutex.unlock (); +} + +void KXinePlayer::updatePosition () { + if (!running || !callback) return; + int pos; + mutex.lock (); + xine_get_pos_length (stream, 0, &pos, &movie_length); + mutex.unlock (); + if (movie_pos != pos) { + movie_pos = pos; + callback->moviePosition (pos/100); + } + QTimer::singleShot (500, this, SLOT (updatePosition ())); +} + +void KXinePlayer::saturation (int val) { + movie_saturation = val; + if (running) { + mutex.lock (); + xine_set_param (stream, XINE_PARAM_VO_SATURATION, val); + mutex.unlock (); + } +} + +void KXinePlayer::hue (int val) { + movie_hue = val; + if (running) { + mutex.lock (); + xine_set_param (stream, XINE_PARAM_VO_HUE, val); + mutex.unlock (); + } +} + +void KXinePlayer::contrast (int val) { + movie_contrast = val; + if (running) { + mutex.lock (); + xine_set_param (stream, XINE_PARAM_VO_CONTRAST, val); + mutex.unlock (); + } +} + +void KXinePlayer::brightness (int val) { + movie_brightness = val; + if (running) { + mutex.lock (); + xine_set_param (stream, XINE_PARAM_VO_BRIGHTNESS, val); + mutex.unlock (); + } +} + +void KXinePlayer::volume (int val) { + movie_volume = val; + if (running) { + mutex.lock (); + xine_set_param( stream, XINE_PARAM_AUDIO_VOLUME, val); + mutex.unlock (); + } +} + +void KXinePlayer::seek (int val) { + if (running) { + fprintf(stderr, "seek %d\n", val); + mutex.lock (); + if (!xine_play (stream, 0, val * 100)) { + fprintf(stderr, "Unable to seek to %d :-(\n", val); + } + mutex.unlock (); + } +} + +bool KXinePlayer::event (QEvent * e) { + switch (e->type()) { + case event_finished: { + fprintf (stderr, "event_finished\n"); + if (audio_vis) { + audio_vis_cfg_entry.num_value = 0; + xine_config_cb (0L, &audio_vis_cfg_entry); + } + mutex.lock (); + running = 0; + firstframe = 0; + if (sub_stream) { + xine_dispose (sub_stream); + sub_stream = 0L; + } + if (stream) { + xine_event_dispose_queue (event_queue); + xine_dispose (stream); + stream = 0L; + } + mutex.unlock (); + //XLockDisplay (display); + //XClearWindow (display, wid); + //XUnlockDisplay (display); + if (callback) + callback->finished (); + else + QTimer::singleShot (0, this, SLOT (quit ())); + break; + } + case event_size: { + if (callback) { + XineMovieParamEvent * se = static_cast <XineMovieParamEvent *> (e); + if (se->length < 0) se->length = 0; + callback->movieParams (se->length/100, se->width, se->height, se->height ? 1.0*se->width/se->height : 1.0, se->alang, se->slang); + if (se->first_frame) { + callback->playing (); + QTimer::singleShot (500, this, SLOT (updatePosition ())); + } + } + break; + } + case event_progress: { + XineProgressEvent * pe = static_cast <XineProgressEvent *> (e); + if (callback) + callback->loadingProgress (pe->progress); + break; + } + case event_url: { + XineURLEvent * ue = static_cast <XineURLEvent *> (e); + if (callback) + callback->subMrl (ue->url, QString ()); + break; + } + case event_title: { + XineTitleEvent * ue = static_cast <XineTitleEvent *> (e); + if (callback) + callback->statusMessage ((int) KMPlayer::Callback::stat_newtitle, ue->title); + break; + } + case event_video: + if (callback) + callback->statusMessage ((int) KMPlayer::Callback::stat_hasvideo, QString ()); + break; + default: + return false; + } + return true; +} + +void KXinePlayer::saveState (QSessionManager & sm) { + if (callback) + sm.setRestartHint (QSessionManager::RestartNever); +} + +XineMovieParamEvent::XineMovieParamEvent(int l, int w, int h, const QStringList & a, const QStringList & s, bool ff) + : QEvent ((QEvent::Type) event_size), + length (l), width (w), height (h), alang (a), slang (s) , first_frame (ff) +{} + +XineURLEvent::XineURLEvent (const QString & u) + : QEvent ((QEvent::Type) event_url), url (u) +{} + +XineTitleEvent::XineTitleEvent (const char * t) + : QEvent ((QEvent::Type) event_title), title (QString::fromUtf8 (t)) +{ + QUrl::decode (title); +} + +XineProgressEvent::XineProgressEvent (const int p) + : QEvent ((QEvent::Type) event_progress), progress (p) +{} + +//static bool translateCoordinates (int wx, int wy, int mx, int my) { +// movie_width +class XEventThread : public QThread { +protected: + void run () { + Time prev_click_time = 0; + int prev_click_x = 0; + int prev_click_y = 0; + while (true) { + XEvent xevent; + XNextEvent(display, &xevent); + switch(xevent.type) { + case ClientMessage: + if (xevent.xclient.message_type == quit_atom) { + fprintf(stderr, "request quit\n"); + return; + } + break; + case KeyPress: + { + XKeyEvent kevent; + KeySym ksym; + char kbuf[256]; + int len; + + kevent = xevent.xkey; + + XLockDisplay(display); + len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); + XUnlockDisplay(display); + fprintf(stderr, "keypressed 0x%x 0x%x\n", kevent.keycode, ksym); + + switch (ksym) { + + case XK_q: + case XK_Q: + xineapp->lock (); + xineapp->stop (); + xineapp->unlock (); + break; + + case XK_p: // previous + mutex.lock (); + if (stream) { + xine_event_t xine_event = { + XINE_EVENT_INPUT_PREVIOUS, + stream, 0L, 0, { 0, 0 } + }; + xine_event_send (stream, &xine_event); + } + mutex.unlock (); + break; + + case XK_n: // next + mutex.lock (); + if (stream) { + xine_event_t xine_event = { + XINE_EVENT_INPUT_NEXT, + stream, 0L, 0, { 0, 0 } + }; + xine_event_send (stream, &xine_event); + } + mutex.unlock (); + break; + + case XK_u: // up menu + mutex.lock (); + if (stream) { + xine_event_t xine_event = { + XINE_EVENT_INPUT_MENU1, + stream, 0L, 0, { 0, 0 } + }; + xine_event_send (stream, &xine_event); + } + mutex.unlock (); + break; + + case XK_r: // root menu + mutex.lock (); + if (stream) { + xine_event_t xine_event = { + XINE_EVENT_INPUT_MENU3, + stream, 0L, 0, { 0, 0 } + }; + xine_event_send (stream, &xine_event); + } + mutex.unlock (); + break; + + case XK_Up: + xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, + (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1)); + break; + + case XK_Down: + xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, + (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1)); + break; + + case XK_plus: + xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, + (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1)); + break; + + case XK_minus: + xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, + (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1)); + break; + + case XK_space: + if(xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE) + xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); + else + xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); + break; + + } + } + break; + + case Expose: + if(xevent.xexpose.count != 0 || !stream || xevent.xexpose.window != wid) + break; + mutex.lock (); + xine_gui_send_vo_data(stream, XINE_GUI_SEND_EXPOSE_EVENT, &xevent); + mutex.unlock (); + break; + + case ConfigureNotify: + { + Window tmp_win; + + width = xevent.xconfigure.width; + height = xevent.xconfigure.height; + if((xevent.xconfigure.x == 0) && (xevent.xconfigure.y == 0)) { + XLockDisplay(display); + XTranslateCoordinates(display, xevent.xconfigure.window, + DefaultRootWindow(xevent.xconfigure.display), + 0, 0, &xpos, &ypos, &tmp_win); + XUnlockDisplay(display); + } + else { + xpos = xevent.xconfigure.x; + ypos = xevent.xconfigure.y; + } + } + + break; + case MotionNotify: + if (stream) { + XMotionEvent *mev = (XMotionEvent *) &xevent; + x11_rectangle_t rect = { mev->x, mev->y, 0, 0 }; + if (xine_gui_send_vo_data (stream, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*) &rect) == -1) + break; + xine_input_data_t data; + data.x = rect.x; + data.y = rect.y; + data.button = 0; + xine_event_t xine_event = { + XINE_EVENT_INPUT_MOUSE_MOVE, + stream, &data, sizeof (xine_input_data_t), + { 0 , 0 } + }; + mutex.lock (); + xine_event_send (stream, &xine_event); + mutex.unlock (); + } + break; + case ButtonPress: { + XButtonEvent *bev = (XButtonEvent *) &xevent; + int dx = prev_click_x - bev->x; + int dy = prev_click_y - bev->y; + if (bev->time - prev_click_time < 400 && + (dx * dx + dy * dy) < 25) { + xineapp->lock (); + if (callback) + callback->toggleFullScreen (); + xineapp->unlock (); + } + prev_click_time = bev->time; + prev_click_x = bev->x; + prev_click_y = bev->y; + if (stream) { + fprintf(stderr, "ButtonPress\n"); + XButtonEvent *bev = (XButtonEvent *) &xevent; + x11_rectangle_t rect = { bev->x, bev->y, 0, 0 }; + if (xine_gui_send_vo_data (stream, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*) &rect) == -1) + break; + xine_input_data_t data; + data.x = rect.x; + data.y = rect.y; + data.button = 1; + xine_event_t xine_event = { + XINE_EVENT_INPUT_MOUSE_BUTTON, + stream, &data, sizeof (xine_input_data_t), + { 0, 0 } + }; + mutex.lock (); + xine_event_send (stream, &xine_event); + mutex.unlock (); + } + break; + } + case NoExpose: + //fprintf (stderr, "NoExpose %lu\n", xevent.xnoexpose.drawable); + break; + case CreateNotify: + fprintf (stderr, "CreateNotify: %lu %lu %d,%d %dx%d\n", + xevent.xcreatewindow.window, xevent.xcreatewindow.parent, + xevent.xcreatewindow.x, xevent.xcreatewindow.y, + xevent.xcreatewindow.width, xevent.xcreatewindow.height); + break; + case DestroyNotify: + fprintf (stderr, "DestroyNotify: %lu\n", xevent.xdestroywindow.window); + break; + default: + if (xevent.type < LASTEvent) + fprintf (stderr, "event %d\n", xevent.type); + } + + if(xevent.type == completion_event && stream) + xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &xevent); + } + } +}; + +int main(int argc, char **argv) { + const char *dvd_device = 0L; + const char *vcd_device = 0L; + const char *grab_device = 0L; + if (!XInitThreads ()) { + fprintf (stderr, "XInitThreads () failed\n"); + return 1; + } + display = XOpenDisplay(NULL); + screen = XDefaultScreen(display); + quit_atom = XInternAtom (display, "kxineplayer_quit", false); + + snprintf(configfile, sizeof (configfile), "%s%s", xine_get_homedir(), "/.xine/config2"); + xineapp = new KXinePlayer (argc, argv); + window_created = true; + QString vo_driver ("auto"); + QString ao_driver ("auto"); + for (int i = 1; i < argc; i++) { + if (!strcmp (argv [i], "-vo") && ++i < argc) { + vo_driver = argv [i]; + } else if (!strcmp (argv [i], "-ao") && ++i < argc) { + ao_driver = argv [i]; + } else if (!strcmp (argv [i], "-dvd-device") && ++i < argc) { + dvd_device = argv [i]; + } else if (!strcmp (argv [i], "-vcd-device") && ++i < argc) { + vcd_device = argv [i]; + } else if (!strcmp (argv [i], "-vd") && ++i < argc) { + grab_device = argv [i]; + } else if ((!strcmp (argv [i], "-wid") || + !strcmp (argv [i], "-window-id")) && ++i < argc) { + wid = atol (argv [i]); + window_created = false; + } else if (!strcmp (argv [i], "-root")) { + wid = XDefaultRootWindow (display); + window_created = false; + } else if (!strcmp (argv [i], "-window")) { + ; + } else if (!strcmp (argv [i], "-sub") && ++i < argc) { + sub_mrl = QString (argv [i]); + } else if (!strcmp (argv [i], "-lang") && ++i < argc) { + slang = alang = QString (argv [i]); + } else if (!strcmp (argv [i], "-v")) { + xine_verbose = true; + } else if (!strcmp (argv [i], "-vv")) { + xine_verbose = xine_vverbose = true; + } else if (!strcmp (argv [i], "-c")) { + wants_config = true; + } else if (!strcmp (argv [i], "-f") && ++i < argc) { + strncpy (configfile, argv [i], sizeof (configfile)); + configfile[sizeof (configfile) - 1] = 0; + } else if (!strcmp (argv [i], "-cb") && ++i < argc) { + QString str = argv [i]; + int pos = str.find ('/'); + if (pos > -1) { + fprintf (stderr, "callback is %s %s\n", str.left (pos).ascii (), str.mid (pos + 1).ascii ()); + callback = new KMPlayer::Callback_stub + (str.left (pos).ascii (), str.mid (pos + 1).ascii ()); + } + } else if (!strcmp (argv [i], "-rec") && i < argc - 1) { + rec_mrl = QString::fromLocal8Bit (argv [++i]); + } else if (!strcmp (argv [i], "-loop") && i < argc - 1) { + repeat_count = atol (argv [++i]); + } else { + if (mrl.startsWith ("-session")) { + delete xineapp; + return 1; + } + mrl = QString::fromLocal8Bit (argv [i]); + } + } + bool config_changed = !QFile (configfile).exists (); + + if (!callback && mrl.isEmpty ()) { + fprintf (stderr, "usage: %s [-vo (xv|xshm)] [-ao (arts|esd|..)] " + "[-f <xine config file>] [-dvd-device <device>] " + "[-vcd-device <device>] [-vd <video device>] " + "[-wid <X11 Window>|-window-id <X11 Window>|-root] " + "[-sub <subtitle url>] [-lang <lang>] [(-v|-vv)] " + "[-cb <DCOP callback name> [-c]] " + "[-loop <repeat>] [<url>]\n", argv[0]); + delete xineapp; + return 1; + } + + XEventThread * eventThread = new XEventThread; + eventThread->start (); + + DCOPClient dcopclient; + dcopclient.registerAs ("kxineplayer"); + Backend player; + + xine = xine_new(); + if (xine_verbose) + xine_engine_set_param (xine, XINE_ENGINE_PARAM_VERBOSITY, xine_vverbose ? XINE_VERBOSITY_DEBUG : XINE_VERBOSITY_LOG); + xine_config_load(xine, configfile); + xine_init(xine); + + xineapp->init (); + + if (dvd_device) + config_changed |= updateConfigEntry (QString ("input.dvd_device"), QString (dvd_device)); + if (vcd_device) + config_changed |= updateConfigEntry (QString ("input.vcd_device"), QString (vcd_device)); + if (grab_device) + config_changed |= updateConfigEntry (QString ("media.video4linux.video_device"), QString (grab_device)); + + if (config_changed) + xine_config_save (xine, configfile); + + QStringList vos = QStringList::split (',', vo_driver); + for (int i = 0; i < vos.size (); i++) { + if (vos[i] == "x11") + vos[i] = "xshm"; + else if (vos[i] == "gl") + vos[i] = "opengl"; + fprintf (stderr, "trying video driver %s ..\n", vos[i].ascii ()); + vo_port = xine_open_video_driver(xine, vos[i].ascii (), + XINE_VISUAL_TYPE_X11, (void *) &vis); + if (vo_port) + break; + } + if (!vo_port) + fprintf (stderr, "no video driver found\n"); + QStringList aos = QStringList::split (',', ao_driver); + for (int i = 0; i < aos.size (); i++) { + fprintf (stderr, "trying audio driver %s ..\n", aos[i].ascii ()); + ao_port = xine_open_audio_driver (xine, aos[i].ascii (), NULL); + if (ao_port) + break; + } + if (!ao_port) + fprintf (stderr, "audio driver initialisation failed\n"); + stream = xine_stream_new (xine, ao_port, vo_port); + + QByteArray buf; + if (wants_config) { + /* TODO? Opening the output drivers in front, will add more config + settings. Unfortunately, that also adds a second in startup.. + const char *const * aops = xine_list_audio_output_plugins (xine); + for (const char *const* aop = aops; *aop; aop++) { + xine_audio_port_t * ap = xine_open_audio_driver (xine, *aop, 0L); + xine_close_audio_driver (xine, ap); + fprintf (stderr, "audio output: %s\n", *aop); + } + const char *const * vops = xine_list_video_output_plugins (xine); + for (const char *const* vop = vops; *vop; vop++) { + xine_video_port_t * vp = xine_open_video_driver (xine, *vop, XINE_VISUAL_TYPE_NONE, 0L); + xine_close_video_driver (xine, vp); + fprintf (stderr, "vidio output: %s\n", *vop); + }*/ + getConfigEntries (buf); + } + if (callback) + callback->started (dcopclient.appId (), buf); + else + ;//printf ("%s\n", QString (buf).ascii ()); + xineapp->exec (); + + if (sub_stream) + xine_dispose (sub_stream); + if (stream) { + xine_event_dispose_queue (event_queue); + xine_dispose (stream); + } + if (ao_port) + xine_close_audio_driver (xine, ao_port); + if (vo_port) + xine_close_video_driver (xine, vo_port); + XLockDisplay(display); + XEvent ev; + ev.xclient.type = ClientMessage; + ev.xclient.serial = 0; + ev.xclient.send_event = true; + ev.xclient.display = display; + ev.xclient.window = wid; + ev.xclient.message_type = quit_atom; + ev.xclient.format = 8; + ev.xclient.data.b[0] = 0; + XSendEvent (display, wid, false, StructureNotifyMask, &ev); + XFlush (display); + XUnlockDisplay(display); + eventThread->wait (500); + delete eventThread; + + xineapp->stop (); + delete xineapp; + + xine_exit (xine); + + fprintf (stderr, "closing display\n"); + XCloseDisplay (display); + fprintf (stderr, "done\n"); + return 0; +} + +#include "xineplayer.moc" diff --git a/src/xineplayer.h b/src/xineplayer.h new file mode 100644 index 0000000..fe7a785 --- /dev/null +++ b/src/xineplayer.h @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2003 by Koos Vriezen <[email protected]> + * + * 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. + **/ + +#ifndef _KXINEPLAYER_H_ +#define _KXINEPLAYER_H_ + +#include <qapplication.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qsessionmanager.h> + +struct XineMovieParamEvent : public QEvent { + XineMovieParamEvent (int l, int w, int h, const QStringList & al, const QStringList & sl, bool ff=false); + int length; + int width; + int height; + QStringList alang; + QStringList slang; + bool first_frame; +}; + +struct XineURLEvent : public QEvent { + XineURLEvent (const QString & u); + QString url; +}; + +struct XineTitleEvent : public QEvent { + XineTitleEvent (const char *); + QString title; +}; + +struct XineProgressEvent : public QEvent { + XineProgressEvent (int p); + int progress; +}; + +class KXinePlayer : public QApplication { + Q_OBJECT +public: + KXinePlayer (int argc, char ** argv); + ~KXinePlayer (); + + void init (); + void finished (); + void saturation (int val); + void hue (int val); + void contrast (int val); + void brightness (int val); + void volume (int val); + void seek (int val); + bool event (QEvent * e); + void setAudioLang (int, const QString &); + void setSubtitle (int, const QString &); +public slots: + void play (int repeat_count); + void stop (); + void pause (); + void updatePosition (); + void postFinished (); +protected: + void saveState (QSessionManager & sm); +}; + +#endif //_KXINEPLAYER_H_ diff --git a/src/xvplayer.cpp b/src/xvplayer.cpp new file mode 100644 index 0000000..7c773c3 --- /dev/null +++ b/src/xvplayer.cpp @@ -0,0 +1,704 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <config.h> +#include <dcopclient.h> +#include <qcstring.h> +#include <qtimer.h> +#include <qfile.h> +#include <qurl.h> +#include <qthread.h> +#include <qmutex.h> +#include <qdom.h> +#include "kmplayer_backend.h" +#include "kmplayer_callback_stub.h" +#include "kmplayer_callback.h" +#include "xvplayer.h" +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> +#include <X11/extensions/Xvlib.h> + + +static char configfile[2048]; + +static Display *display; +static KXVideoPlayer *xvapp; +static KMPlayer::Callback_stub * callback; +static Window wid; +static GC gc; +static bool window_created = true; +static bool wants_config; +static bool verbose; +static bool running; +static bool have_freq; +static bool xv_success; +static bool reset_xv_autopaint_colorkey; +static bool reset_xv_mute; +static int xvport; +static int xv_encoding = -1; +static QString xv_norm; +static int xv_frequency; +static int screen; +static int movie_width; +static int movie_height; +static int current_volume; +static int tmp_volume; +static const int start_vol_timeout = 100; +static const int inc_vol_timeout = 20; +Atom xv_enc_atom; +Atom xv_hue_atom; +Atom xv_saturation_atom; +Atom xv_brightness_atom; +Atom xv_contrast_atom; +Atom xv_freq_atom; +Atom xv_volume_atom; +Atom xv_mute_atom; +Atom xv_autopaint_colorkey_atom; +enum { + limit_volume = 0, + limit_hue, limit_contrast, limit_brightness, limit_saturation, + limit_last +}; +static struct Limit { int min; int max; } xv_limits [limit_last]; +static QString elmentry ("entry"); +static QString elmitem ("item"); +static QString attname ("name"); +static QString atttype ("type"); +static QString attdefault ("DEFAULT"); +static QString attvalue ("value"); +//static QString attstart ("START"); +//static QString attend ("END"); +//static QString valrange ("range"); +//static QString valnum ("num"); +//static QString valbool ("bool"); +//static QString valenum ("enum"); +//static QString valstring ("string"); +static QString valtree ("tree"); +static QByteArray config_buf; + +extern "C" { + +} // extern "C" + +static void putVideo () { + XWindowAttributes attr; + XGetWindowAttributes (display, wid, &attr); + XvPutVideo (display, xvport, wid, gc, 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); +} + +using namespace KMPlayer; + +Backend::Backend () + : DCOPObject (QCString ("Backend")) { +} + +Backend::~Backend () {} + +void Backend::setURL (QString) { +} + +void Backend::setSubTitleURL (QString) { +} + +void Backend::play (int) { + xvapp->play (); +} + +void Backend::stop () { + QTimer::singleShot (0, xvapp, SLOT (stop ())); +} + +void Backend::pause () { +} + +void Backend::seek (int, bool /*absolute*/) { +} + +void Backend::hue (int h, bool) { + if (xv_limits[limit_hue].max > xv_limits[limit_hue].min) + xvapp->hue ((h + 100) * (xv_limits[limit_hue].max - xv_limits[limit_hue].min)/200 + xv_limits[limit_hue].min); +} + +void Backend::saturation (int s, bool) { + if (xv_limits[limit_saturation].max > xv_limits[limit_saturation].min) + xvapp->saturation ((s + 100) * (xv_limits[limit_saturation].max - xv_limits[limit_saturation].min)/200 + xv_limits[limit_saturation].min); +} + +void Backend::contrast (int c, bool) { + if (xv_limits[limit_contrast].max > xv_limits[limit_contrast].min) + xvapp->contrast ((c + 100)*(xv_limits[limit_contrast].max - xv_limits[limit_contrast].min)/200 + xv_limits[limit_contrast].min); +} + +void Backend::brightness (int b, bool) { + if (xv_limits[limit_brightness].max > xv_limits[limit_brightness].min) + xvapp->brightness ((b + 100)*(xv_limits[limit_brightness].max - xv_limits[limit_brightness].min)/200 + xv_limits[limit_brightness].min); +} + +void Backend::volume (int v, bool) { + if (xv_limits[limit_volume].max > xv_limits[limit_volume].min) + xvapp->volume (v*(xv_limits[limit_volume].max - xv_limits[limit_volume].min)/100 + xv_limits[limit_volume].min); +} + +void Backend::frequency (int f) { + xvapp->frequency (f); +} + +void Backend::setAudioLang (int, QString) { +} + +void Backend::setSubtitle (int, QString) { +} + +void Backend::quit () { + delete callback; + callback = 0L; + if (running) + stop (); + else + QTimer::singleShot (0, qApp, SLOT (quit ())); +} + +bool updateConfigEntry (const QString & name, const QString & value) { + fprintf (stderr, "%s=%s\n", name.ascii (), (const char *) value.local8Bit ()); + return true; +} + +void Backend::setConfig (QByteArray data) { + QString err; + int line, column; + QDomDocument dom; + if (dom.setContent (data, false, &err, &line, &column)) { + if (dom.childNodes().length() == 1) { + for (QDomNode node = dom.firstChild().firstChild(); + !node.isNull (); + node = node.nextSibling ()) { + QDomNamedNodeMap attr = node.attributes (); + updateConfigEntry (attr.namedItem (attname).nodeValue (), + attr.namedItem (attvalue).nodeValue ()); + } + } else + err = QString ("invalid data"); + } + if (callback) + callback->errorMessage (0, err); +} + +bool Backend::isPlaying () { + return running; +} + +KXVideoPlayer::KXVideoPlayer (int _argc, char ** _argv) + : QApplication (_argc, _argv, false), mute_timer (0) { +} + +void KXVideoPlayer::init () { + int xpos = 0; + int ypos = 0; + int width = 320; + int height = 200; + + XLockDisplay(display); + if (window_created) + wid = XCreateSimpleWindow(display, XDefaultRootWindow(display), + xpos, ypos, width, height, 1, 0, 0); + if (!callback) + QTimer::singleShot (10, this, SLOT (play ())); + XSelectInput (display, wid, + (PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask)); // | SubstructureNotifyMask)); + XvAdaptorInfo * ai; + unsigned int adaptors; + xv_success = true; + QDomDocument doc; + QDomElement root = doc.createElement (QString ("document")); + if (XvQueryAdaptors (display, XDefaultRootWindow (display), &adaptors, &ai) == Success) { + QDomElement elm = doc.createElement (elmentry); + elm.setAttribute (attname, QString ("XVideo")); + elm.setAttribute (atttype, valtree); + for (unsigned i = 0; i < adaptors; i++) { + if ((ai[i].type & XvInputMask) && + (ai[i].type & XvVideoMask) && + ai[i].base_id > 0) { + int port = ai[i].base_id; + fprintf (stderr, "xvport %d\n", port); + bool freq_found = false; + XvAttribute *attributes = 0L; + int nr_attr, cur_val; + attributes = XvQueryPortAttributes (display, port, &nr_attr); + if (attributes) { + for (int i = 0; i < nr_attr; i++) { + if (!strcmp (attributes[i].name, "XV_FREQ")) + freq_found = true; + Atom atom = XInternAtom (display, attributes[i].name, false); + fprintf (stderr, "%s[%d] (%d .. %d)", attributes[i].name, ( int ) atom, attributes[i].min_value, attributes[i].max_value); + if ((attributes[i].flags & XvGettable) && XvGetPortAttribute (display, port, atom, &cur_val) == Success) + fprintf (stderr, " current: %d", cur_val); + fprintf (stderr, "\n"); + } + XFree(attributes); + } + if (!xvport && ((xv_frequency > 0) == freq_found)) { + fprintf (stderr, "using xvport %d\n", port); + xvport = port; + } + if (xvport == port) + have_freq = freq_found; + XvEncodingInfo * encodings = 0L; + unsigned nr_encode; + XvQueryEncodings (display, port, &nr_encode, &encodings); + if (encodings) { + QDomElement port_item = doc.createElement (QString("Port")); + port_item.setAttribute (attvalue, QString::number (port)); + if (freq_found) + port_item.setAttribute (QString("FREQ"), QString("1")); + for (unsigned i = 0; i < nr_encode; i++) { + if (strcmp (encodings[i].name, "XV_IMAGE")) { + if (xvport == port && xv_encoding < 0 && !xv_norm.isEmpty () && QString (encodings[i].name).lower ().startsWith(xv_norm.lower ())) + xv_encoding = encodings[i].encoding_id; + if (port == xvport && encodings[i].encoding_id == xv_encoding) { + movie_width = encodings[i].width; + movie_height = encodings[i].height; + } + QDomElement item = doc.createElement (QString ("Input")); + item.setAttribute (attvalue, QString::number (encodings[i].encoding_id)); + item.setAttribute (attname, QString (encodings[i].name)); + port_item.appendChild (item); + fprintf (stderr, " encoding: %d %s\n", ( int ) encodings[i].encoding_id, encodings[i].name); + } + } + elm.appendChild (port_item); + XvFreeEncodingInfo (encodings); + } + } + } + root.appendChild (elm); + XvFreeAdaptorInfo(ai); + } + doc.appendChild (root); + QCString exp = doc.toCString (); + config_buf = exp; + //fprintf (stderr, "%s\n", (const char *)exp); + config_buf.resize (exp.length ()); // strip terminating \0 + + if (xvport <= 0) { + fprintf (stderr, "no valid xvport found\n"); + xv_success = false; + return; + } + if (window_created) { + fprintf (stderr, "map %lu\n", wid); + if (movie_width > 0 && movie_height > 0) + XResizeWindow (display, wid, movie_width, movie_height); + XMapRaised(display, wid); + XSync(display, False); + } + XUnlockDisplay(display); + if (!xv_success) + fprintf (stderr, "Failed to init %d port\n", xvport); +} + +KXVideoPlayer::~KXVideoPlayer () { + if (window_created) { + XLockDisplay (display); + fprintf (stderr, "unmap %lu\n", wid); + XUnmapWindow (display, wid); + XDestroyWindow(display, wid); + XSync (display, False); + XUnlockDisplay (display); + } + xvapp = 0L; +} + +void getConfigEntries (QByteArray & buf) { + QDomDocument doc; + QDomElement root = doc.createElement (QString ("document")); + doc.appendChild (root); + QCString exp = doc.toCString (); + buf = exp; + buf.resize (exp.length ()); // strip terminating \0 +} + +void KXVideoPlayer::play () { + fprintf (stderr, "play xv://%d:%d/%d\n", xvport, xv_encoding, xv_frequency); + if (!xv_success) + return; + if (callback && movie_width > 0 && movie_height > 0) + callback->movieParams (0, movie_width, movie_height, 1.0*movie_width/movie_height, QStringList (), QStringList ()); + XLockDisplay (display); + if (!running && XvGrabPort (display, xvport, CurrentTime) == Success) { + gc = XCreateGC (display, wid, 0, NULL); + XvSelectPortNotify (display, xvport, 1); + XvSelectVideoNotify (display, wid, 1); + int nr, cur_val; + if (XvGetPortAttribute (display, xvport, xv_autopaint_colorkey_atom, &cur_val) == Success && cur_val == 0) { + fprintf (stderr, "XV_AUTOPAINT_COLORKEY is 0\n"); + XvSetPortAttribute (display, xvport, xv_autopaint_colorkey_atom, 1); + reset_xv_autopaint_colorkey = true; + } + XvAttribute *attributes = XvQueryPortAttributes (display, xvport, &nr); + if (attributes) { + for (int i = 0; i < nr; i++) { + Limit * limit = 0; + Atom atom = XInternAtom (display, attributes[i].name, false); + if (atom == xv_volume_atom) { + limit = xv_limits + limit_volume; + XvGetPortAttribute (display, xvport, + xv_volume_atom, ¤t_volume); + } else if (atom == xv_hue_atom) { + limit = xv_limits + limit_hue; + } else if (atom == xv_saturation_atom) { + limit = xv_limits + limit_saturation; + } else if (atom == xv_brightness_atom) { + limit = xv_limits + limit_brightness; + } else if (atom == xv_contrast_atom) { + limit = xv_limits + limit_contrast; + } else + continue; + limit->min = attributes[i].min_value; + limit->max = attributes[i].max_value; + } + XFree (attributes); + } + if (xv_frequency > 0) + XvSetPortAttribute (display, xvport, xv_freq_atom, int (1.0*xv_frequency/62.5)); + if (xv_encoding >= 0) + XvSetPortAttribute (display, xvport, xv_enc_atom, xv_encoding); + if (XvGetPortAttribute (display, xvport, xv_mute_atom, &cur_val) == + Success && cur_val == 1) { + fprintf (stderr, "XV_MUTE is 1\n"); + if (xv_limits[limit_volume].min != xv_limits[limit_volume].max) { + tmp_volume = xv_limits[limit_volume].min; + XvSetPortAttribute(display, xvport, xv_volume_atom, tmp_volume); + mute_timer = startTimer (start_vol_timeout); + } + XvSetPortAttribute (display, xvport, xv_mute_atom, 0); + reset_xv_mute = true; + } + //XvGetVideo (.. + running = true; + } + if (running) { + putVideo (); + if (callback) { + callback->playing (); + callback->statusMessage ((int) KMPlayer::Callback::stat_hasvideo, QString ()); + } + } + XUnlockDisplay (display); +} + +void KXVideoPlayer::stop () { + if (mute_timer) { + killTimer (mute_timer); + mute_timer = 0; + } + if (running) { + running = false; + XLockDisplay (display); + XvStopVideo (display, xvport, wid); + if (reset_xv_autopaint_colorkey) { + XvSetPortAttribute (display, xvport, xv_autopaint_colorkey_atom, 0); + reset_xv_autopaint_colorkey = false; + } + if (reset_xv_mute) { + XvSetPortAttribute (display, xvport, xv_mute_atom, 1); + reset_xv_mute = false; + } + XvUngrabPort (display, xvport, CurrentTime); + XFreeGC (display, gc); + XClearArea (display, wid, 0, 0, 0, 0, true); + XUnlockDisplay (display); + } + if (callback) + callback->finished (); + else + QTimer::singleShot (0, qApp, SLOT (quit ())); +} + +void KXVideoPlayer::finished () { + QTimer::singleShot (10, this, SLOT (stop ())); +} + +void KXVideoPlayer::saturation (int val) { + XLockDisplay(display); + XvSetPortAttribute (display, xvport, xv_saturation_atom, val); + XFlush (display); + XUnlockDisplay(display); +} + +void KXVideoPlayer::hue (int val) { + XLockDisplay(display); + XvSetPortAttribute (display, xvport, xv_hue_atom, val); + XFlush (display); + XUnlockDisplay(display); +} + +void KXVideoPlayer::contrast (int val) { + XLockDisplay(display); + XvSetPortAttribute (display, xvport, xv_contrast_atom, val); + XFlush (display); + XUnlockDisplay(display); +} + +void KXVideoPlayer::brightness (int val) { + XLockDisplay(display); + XvSetPortAttribute (display, xvport, xv_brightness_atom, val); + XFlush (display); + XUnlockDisplay(display); +} + +void KXVideoPlayer::volume (int val) { + current_volume = val; + if (mute_timer) + return; + XLockDisplay(display); + XvSetPortAttribute (display, xvport, xv_volume_atom, val); + XFlush (display); + XUnlockDisplay(display); +} + +void KXVideoPlayer::frequency (int val) { + // this doesn't work, changing frequency kills audio for me + if (mute_timer) { + killTimer (mute_timer); + mute_timer = 0; + } + xv_frequency = val; + if (running && have_freq) { + XLockDisplay(display); + if (xv_limits[limit_volume].min != xv_limits[limit_volume].max) { + tmp_volume = xv_limits[limit_volume].min; + XvSetPortAttribute (display, xvport, xv_volume_atom, tmp_volume); + mute_timer = startTimer (start_vol_timeout); + XFlush (display); + XvSetPortAttribute (display, xvport, xv_mute_atom, 0); + } + XvSetPortAttribute (display, xvport, xv_freq_atom, int (1.0*val/6.25)); + XFlush (display); + XUnlockDisplay(display); + } +} + +void KXVideoPlayer::saveState (QSessionManager & sm) { + if (callback) + sm.setRestartHint (QSessionManager::RestartNever); +} + +void KXVideoPlayer::timerEvent (QTimerEvent * e) { + if (e->timerId () == mute_timer) { + int step = (current_volume - xv_limits[limit_volume].min) / 20; + if (step > 0 && tmp_volume == xv_limits[limit_volume].min) { + killTimer (mute_timer); + mute_timer = startTimer (inc_vol_timeout); + } + tmp_volume += step; + if (tmp_volume >= current_volume || step <= 0) { + tmp_volume = current_volume; + killTimer (mute_timer); + mute_timer = 0; + } + XLockDisplay(display); + XvSetPortAttribute (display, xvport, xv_volume_atom, tmp_volume); + XFlush (display); + XUnlockDisplay(display); + } else + killTimer (e->timerId ()); +} + +class XEventThread : public QThread { +protected: + void run () { + Time prev_click_time = 0; + int prev_click_x = 0; + int prev_click_y = 0; + while (true) { + XEvent xevent; + XNextEvent(display, &xevent); + switch(xevent.type) { + case ClientMessage: + if (xevent.xclient.format == 8 && + !strncmp(xevent.xclient.data.b, "quit_now", 8)) { + fprintf(stderr, "request quit\n"); + return; + } + break; + case KeyPress: { + XKeyEvent kevent; + KeySym ksym; + char kbuf[256]; + int len; + kevent = xevent.xkey; + XLockDisplay(display); + len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); + XUnlockDisplay(display); + fprintf(stderr, "keypressed 0x%x 0x%x\n", ( int ) kevent.keycode, ( int ) ksym); + switch (ksym) { + case XK_q: + case XK_Q: + xvapp->lock (); + xvapp->stop (); + xvapp->unlock (); + break; + } + break; + } + case Expose: + if(xevent.xexpose.count != 0 || xevent.xexpose.window != wid) + break; + break; + + case ConfigureNotify: + if (::running) + putVideo (); + break; + case XvVideoNotify: + fprintf (stderr, "xvevent %lu\n", ((XvEvent*)&xevent)->xvvideo.reason); + break; + case ButtonPress: { + XButtonEvent *bev = (XButtonEvent *) &xevent; + int dx = prev_click_x - bev->x; + int dy = prev_click_y - bev->y; + if (bev->time - prev_click_time < 400 && + (dx * dx + dy * dy) < 25) { + xvapp->lock (); + if (callback) + callback->toggleFullScreen (); + xvapp->unlock (); + } + prev_click_time = bev->time; + prev_click_x = bev->x; + prev_click_y = bev->y; + break; + } + default: + if (xevent.type < LASTEvent) { + //fprintf (stderr, "event %d\n", xevent.type); + } + } + } + } +}; + +int main(int argc, char **argv) { + if (!XInitThreads ()) { + fprintf (stderr, "XInitThreads () failed\n"); + return 1; + } + display = XOpenDisplay(NULL); + screen = XDefaultScreen(display); + + unsigned int ver, rel, req, evb, err; + if (XvQueryExtension (display, &ver, &rel, &req, &evb, &err) != Success) { + fprintf (stderr, "XVideo not supported on display\n"); + XCloseDisplay (display); + return 1; + } + xv_enc_atom = XInternAtom (display, "XV_ENCODING", false); + xv_hue_atom = XInternAtom (display, "XV_HUE", false); + xv_saturation_atom = XInternAtom (display, "XV_SATURATION", false); + xv_brightness_atom = XInternAtom (display, "XV_BRIGHTNESS", false); + xv_contrast_atom = XInternAtom (display, "XV_CONTRAST", false); + xv_freq_atom = XInternAtom (display, "XV_FREQ", false); + xv_volume_atom = XInternAtom (display, "XV_VOLUME", false); + xv_mute_atom = XInternAtom (display, "XV_MUTE", false); + xv_autopaint_colorkey_atom = XInternAtom (display, "XV_AUTOPAINT_COLORKEY", false); + + xvapp = new KXVideoPlayer (argc, argv); + + for(int i = 1; i < argc; i++) { + if (!strcmp (argv [i], "-port")) { + xvport = strtol (argv [++i], 0L, 10); + } else if (!strcmp (argv [i], "-wid") || !strcmp (argv [i], "-window-id")) { + wid = atol (argv [++i]); + window_created = false; + } else if (!strcmp (argv [i], "-root")) { + wid = XDefaultRootWindow (display); + window_created = false; + } else if (!strcmp (argv [i], "-window")) { + ; + } else if (!strcmp (argv [i], "-v")) { + verbose = true; + } else if (!strcmp (argv [i], "-c")) { + wants_config = true; + } else if (!strcmp (argv [i], "-f") && i < argc - 1) { + strncpy (configfile, argv [++i], sizeof (configfile)); + configfile[sizeof (configfile) - 1] = 0; + } else if (!strcmp (argv [i], "-cb")) { + QString str = argv [++i]; + int pos = str.find ('/'); + if (pos > -1) { + fprintf (stderr, "callback is %s %s\n", str.left (pos).ascii (), str.mid (pos + 1).ascii ()); + callback = new KMPlayer::Callback_stub + (str.left (pos).ascii (), str.mid (pos + 1).ascii ()); + } + } else if (!strcmp (argv [i], "-enc")) { + xv_encoding = strtol (argv [++i], 0L, 10); + } else if (!strcmp (argv [i], "-norm")) { + xv_norm = argv [++i]; + } else if (!strcmp (argv [i], "-freq")) { + xv_frequency = strtol (argv [++i], 0L, 10); + } else { + fprintf (stderr, "usage: %s [-port <xv port>] [-enc <encoding>] [-freq <frequency>] [-f <config file>] [-v] [(-wid|-window-id) <window>] [(-root|-window)] [-cb <DCOP callback name> [-c]]\n", argv[0]); + delete xvapp; + return 1; + } + } + + DCOPClient dcopclient; + dcopclient.registerAs ("kxvideoplayer"); + Backend player; + + XEventThread * eventThread = new XEventThread; + eventThread->start (); + + xvapp->init (); + + if (callback) + callback->started (dcopclient.appId (), config_buf); + + xvapp->exec (); + + XLockDisplay(display); + XClientMessageEvent ev = { + ClientMessage, 0, true, display, wid, + XInternAtom (display, "XVIDEO", false), 8, {"quit_now"} + }; + XSendEvent (display, wid, false, StructureNotifyMask, (XEvent *) & ev); + XFlush (display); + XUnlockDisplay(display); + eventThread->wait (500); + delete eventThread; + + xvapp->stop (); + delete xvapp; + + fprintf (stderr, "closing display\n"); + XCloseDisplay (display); + fprintf (stderr, "done\n"); + return 0; +} + +#include "xvplayer.moc" diff --git a/src/xvplayer.h b/src/xvplayer.h new file mode 100644 index 0000000..9782fc6 --- /dev/null +++ b/src/xvplayer.h @@ -0,0 +1,56 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen <[email protected]> + + 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., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _K_XV_PLAYER_H_ +#define _K_XV_PLAYER_H_ + +#include <qapplication.h> +#include <qstring.h> +#include <qsessionmanager.h> + +class KXVideoPlayer : public QApplication { + Q_OBJECT +public: + KXVideoPlayer (int argc, char ** argv); + ~KXVideoPlayer (); + + void init (); + void finished (); + void saturation (int val); + void hue (int val); + void contrast (int val); + void brightness (int val); + void volume (int val); + void frequency (int val); + //void seek (int val); + //bool event (QEvent * e); +public slots: + void play (); + void stop (); + //void pause (); + //void updatePosition (); + //void postFinished (); +protected: + void saveState (QSessionManager & sm); + void timerEvent (QTimerEvent *); +private: + int mute_timer; +}; + +#endif //_K_XV_PLAYER_H_ |